Skip to main content

simd_brotli/enc/
brotli_bit_stream.rs

1#![allow(unknown_lints)]
2#![allow(unused_macros)]
3
4use core::cmp::{max, min};
5#[cfg(feature = "std")]
6use std::io::Write;
7
8use super::super::alloc;
9use super::super::alloc::{Allocator, SliceWrapper, SliceWrapperMut};
10use super::super::dictionary::{
11    kBrotliDictionary, kBrotliDictionaryOffsetsByLength, kBrotliDictionarySizeBitsByLength,
12};
13use super::super::transform::TransformDictionaryWord;
14use super::block_split::BlockSplit;
15use super::combined_alloc::BrotliAlloc;
16use super::command::{Command, GetCopyLengthCode, GetInsertLengthCode};
17use super::constants::{
18    BROTLI_CONTEXT_LUT, BROTLI_NUM_BLOCK_LEN_SYMBOLS, BROTLI_NUM_COMMAND_SYMBOLS,
19    BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS, BROTLI_NUM_LITERAL_SYMBOLS, kCodeLengthBits,
20    kCodeLengthDepth, kCopyBase, kCopyExtra, kInsBase, kInsExtra, kNonZeroRepsBits,
21    kNonZeroRepsDepth, kSigned3BitContextLookup, kStaticCommandCodeBits, kStaticCommandCodeDepth,
22    kStaticDistanceCodeBits, kStaticDistanceCodeDepth, kUTF8ContextLookup, kZeroRepsBits,
23    kZeroRepsDepth,
24};
25use super::context_map_entropy::{ContextMapEntropy, SpeedAndMax, speed_to_tuple};
26use super::entropy_encode::{
27    BrotliConvertBitDepthsToSymbols, BrotliCreateHuffmanTree, BrotliSetDepth,
28    BrotliWriteHuffmanTree, HuffmanComparator, HuffmanTree, SortHuffmanTreeItems,
29};
30use super::histogram::{
31    ContextType, HistogramAddItem, HistogramCommand, HistogramDistance, HistogramLiteral,
32};
33use super::input_pair::{InputPair, InputReference, InputReferenceMut};
34use super::interface::StaticCommand;
35use super::static_dict::kNumDistanceCacheEntries;
36use super::util::floatX;
37use super::{find_stride, interface, prior_eval, stride_eval};
38use crate::VERSION;
39use crate::enc::backward_references::BrotliEncoderParams;
40use crate::enc::combined_alloc::{alloc_default, alloc_or_default, allocate};
41
42pub struct PrefixCodeRange {
43    pub offset: u32,
44    pub nbits: u32,
45}
46pub const MAX_SIMPLE_DISTANCE_ALPHABET_SIZE: usize = 140;
47
48fn window_size_from_lgwin(lgwin: i32) -> usize {
49    (1 << lgwin) - 16usize
50}
51
52struct CommandQueue<'a, Alloc: BrotliAlloc + 'a> {
53    mb: InputPair<'a>,
54    // TODO: delete unused fields
55    #[allow(dead_code)]
56    mb_byte_offset: usize,
57    mc: &'a mut Alloc,
58    queue: <Alloc as Allocator<StaticCommand>>::AllocatedMemory,
59    pred_mode: interface::PredictionModeContextMap<InputReferenceMut<'a>>,
60    loc: usize,
61    entropy_tally_scratch: find_stride::EntropyTally<Alloc>,
62    best_strides_per_block_type: <Alloc as Allocator<u8>>::AllocatedMemory,
63    entropy_pyramid: find_stride::EntropyPyramid<Alloc>,
64    context_map_entropy: ContextMapEntropy<'a, Alloc>,
65    #[allow(dead_code)]
66    stride_detection_quality: u8,
67    #[allow(dead_code)]
68    high_entropy_detection_quality: u8,
69    block_type_literal: u8,
70    #[allow(dead_code)]
71    best_stride_index: usize,
72    overfull: bool,
73}
74
75impl<'a, Alloc: BrotliAlloc> CommandQueue<'a, Alloc> {
76    fn new(
77        alloc: &'a mut Alloc,
78        num_commands: usize,
79        pred_mode: interface::PredictionModeContextMap<InputReferenceMut<'a>>,
80        mb: InputPair<'a>,
81        stride_detection_quality: u8,
82        high_entropy_detection_quality: u8,
83        context_map_entropy: ContextMapEntropy<'a, Alloc>,
84        best_strides: <Alloc as Allocator<u8>>::AllocatedMemory,
85        entropy_tally_scratch: find_stride::EntropyTally<Alloc>,
86        entropy_pyramid: find_stride::EntropyPyramid<Alloc>,
87    ) -> CommandQueue<'a, Alloc> {
88        // assume no more than 1/16 of the stream is block_types which may chop up literals
89        // also there's the first btypel and a potential wrap around the ring buffer
90        let queue = allocate::<StaticCommand, _>(alloc, num_commands * 17 / 16 + 4);
91        CommandQueue {
92            mc: alloc,
93            queue, // always need a spare command in case the ring buffer splits a literal into two
94            pred_mode,
95            mb,
96            mb_byte_offset: 0,
97            loc: 0,
98            best_strides_per_block_type: best_strides,
99            entropy_tally_scratch,
100            entropy_pyramid,
101            stride_detection_quality,
102            high_entropy_detection_quality,
103            context_map_entropy,
104            block_type_literal: 0,
105            best_stride_index: 0,
106            overfull: false,
107        }
108    }
109    fn full(&self) -> bool {
110        self.loc == self.queue.len()
111    }
112    fn error_if_full(&mut self) {
113        if self.full() {
114            self.overfull = true;
115        }
116    }
117    fn clear(&mut self) {
118        self.loc = 0;
119        self.block_type_literal = 0;
120    }
121    fn free<Cb>(&mut self, callback: &mut Cb) -> Result<(), ()>
122    where
123        Cb: FnMut(
124            &mut interface::PredictionModeContextMap<InputReferenceMut>,
125            &mut [interface::StaticCommand],
126            InputPair,
127            &mut Alloc,
128        ),
129    {
130        callback(
131            &mut self.pred_mode,
132            self.queue.slice_mut().split_at_mut(self.loc).0,
133            self.mb,
134            self.mc,
135        );
136        self.clear();
137        self.entropy_tally_scratch.free(self.mc);
138        self.entropy_pyramid.free(self.mc);
139        self.context_map_entropy.free(self.mc);
140        <Alloc as Allocator<StaticCommand>>::free_cell(self.mc, core::mem::take(&mut self.queue));
141        <Alloc as Allocator<u8>>::free_cell(
142            self.mc,
143            core::mem::take(&mut self.best_strides_per_block_type),
144        );
145        if self.overfull {
146            return Err(());
147        }
148        Ok(())
149    }
150}
151
152impl<'a, Alloc: BrotliAlloc> interface::CommandProcessor<'a> for CommandQueue<'a, Alloc> {
153    fn push(&mut self, val: interface::Command<InputReference<'a>>) {
154        if self.full() {
155            let mut tmp = allocate::<StaticCommand, _>(self.mc, self.queue.slice().len() * 2);
156            tmp.slice_mut()
157                .split_at_mut(self.queue.slice().len())
158                .0
159                .copy_from_slice(self.queue.slice());
160            <Alloc as Allocator<StaticCommand>>::free_cell(
161                self.mc,
162                core::mem::replace(&mut self.queue, tmp),
163            );
164        }
165        if !self.full() {
166            self.queue.slice_mut()[self.loc] = val.freeze();
167            self.loc += 1;
168        } else {
169            self.error_if_full();
170        }
171    }
172    fn push_block_switch_literal(&mut self, block_type: u8) {
173        self.push(interface::Command::BlockSwitchLiteral(
174            interface::LiteralBlockSwitch::new(block_type, 0),
175        ))
176    }
177}
178
179#[cfg(feature = "std")]
180fn warn_on_missing_free() {
181    let _err = ::std::io::stderr()
182        .write(b"Need to free entropy_tally_scratch before dropping CommandQueue\n");
183}
184#[cfg(not(feature = "std"))]
185fn warn_on_missing_free() {
186    // no way to warn in this case
187}
188impl<'a, Alloc: BrotliAlloc> Drop for CommandQueue<'a, Alloc> {
189    fn drop(&mut self) {
190        if !self.entropy_tally_scratch.is_free() {
191            warn_on_missing_free();
192        }
193    }
194}
195#[cfg(not(feature = "billing"))]
196fn best_singleton_speed_log(_name: &str, _data: &[SpeedAndMax; 2], _cost: &[floatX; 2]) {}
197#[cfg(feature = "billing")]
198fn best_singleton_speed_log(name: &str, data: &[SpeedAndMax; 2], cost: &[floatX; 2]) {
199    println!(
200        "{} hi cost: {} lo cost: {}   speeds {:?} {:?}",
201        name, cost[1], cost[0], data[1], data[0]
202    );
203}
204
205#[cfg(not(feature = "billing"))]
206fn best_speed_log(_name: &str, _data: &[SpeedAndMax; 2], _cost: &[floatX; 2]) {}
207#[cfg(feature = "billing")]
208fn best_speed_log(name: &str, data: &[SpeedAndMax; 2], cost: &[floatX; 2]) {
209    for high in 0..2 {
210        println!(
211            "{} Speed [ inc: {}, max: {}, algo: {} ] cost: {}",
212            name,
213            if high != 0 { "hi" } else { "lo" },
214            data[high].0,
215            data[high].1,
216            cost[high]
217        );
218    }
219}
220
221fn process_command_queue<'a, CmdProcessor: interface::CommandProcessor<'a>>(
222    command_queue: &mut CmdProcessor,
223    input: InputPair<'a>,
224    commands: &[Command],
225    dist_cache: &[i32; kNumDistanceCacheEntries],
226    mut recoder_state: RecoderState,
227    block_type: &MetaBlockSplitRefs,
228    params: &BrotliEncoderParams,
229    context_type: Option<ContextType>,
230) -> RecoderState {
231    let mut input_iter = input;
232    let mut local_dist_cache = [0i32; kNumDistanceCacheEntries];
233    local_dist_cache.copy_from_slice(&dist_cache[..]);
234    let mut btypel_counter = 0usize;
235    let mut btypec_counter = 0usize;
236    let mut btyped_counter = 0usize;
237    let mut btypel_sub = if block_type.btypel.num_types == 1 {
238        1u32 << 31
239    } else {
240        block_type.btypel.lengths[0]
241    };
242    let mut btypec_sub = if block_type.btypec.num_types == 1 {
243        1u32 << 31
244    } else {
245        block_type.btypec.lengths[0]
246    };
247    let mut btyped_sub = if block_type.btyped.num_types == 1 {
248        1u32 << 31
249    } else {
250        block_type.btyped.lengths[0]
251    };
252    {
253        command_queue.push_block_switch_literal(0);
254    }
255    let mut mb_len = input.len();
256    for cmd in commands.iter() {
257        let (inserts, interim) = input_iter.split_at(min(cmd.insert_len_ as usize, mb_len));
258        recoder_state.num_bytes_encoded += inserts.len();
259        let _copy_cursor = input.len() - interim.len();
260        // let distance_context = cmd.distance_context();
261        let copylen_code = cmd.copy_len_code();
262
263        let (prev_dist_index, dist_offset) = cmd.distance_index_and_offset(&params.dist);
264        let final_distance: usize;
265        if prev_dist_index == 0 {
266            final_distance = dist_offset as usize;
267        } else {
268            final_distance =
269                (local_dist_cache[prev_dist_index - 1] as isize + dist_offset) as usize;
270        }
271        let copy_len = copylen_code as usize;
272        let actual_copy_len: usize;
273        let max_distance = min(
274            recoder_state.num_bytes_encoded,
275            window_size_from_lgwin(params.lgwin),
276        );
277        assert!(inserts.len() <= mb_len);
278        if inserts.len() != 0 {
279            let mut tmp_inserts = inserts;
280            while tmp_inserts.len() > btypel_sub as usize {
281                // we have to divide some:
282                let (in_a, in_b) = tmp_inserts.split_at(btypel_sub as usize);
283                if in_a.len() != 0 {
284                    if context_type.is_some() {
285                        command_queue.push_literals(&in_a);
286                    } else if params.high_entropy_detection_quality == 0 {
287                        command_queue.push_literals(&in_a);
288                    } else {
289                        command_queue.push_rand_literals(&in_a);
290                    }
291                }
292                mb_len -= in_a.len();
293                tmp_inserts = in_b;
294                btypel_counter += 1;
295                if block_type.btypel.types.len() > btypel_counter {
296                    btypel_sub = block_type.btypel.lengths[btypel_counter];
297                    command_queue
298                        .push_block_switch_literal(block_type.btypel.types[btypel_counter]);
299                } else {
300                    btypel_sub = 1u32 << 31;
301                }
302            }
303            if context_type.is_some() {
304                command_queue.push_literals(&tmp_inserts);
305            } else if params.high_entropy_detection_quality == 0 {
306                command_queue.push_literals(&tmp_inserts);
307            } else {
308                command_queue.push_rand_literals(&tmp_inserts);
309            }
310            if tmp_inserts.len() != 0 {
311                mb_len -= tmp_inserts.len();
312                btypel_sub -= tmp_inserts.len() as u32;
313            }
314        }
315        if final_distance > max_distance {
316            // is dictionary
317            assert!(copy_len >= 4);
318            assert!(copy_len < 25);
319            let dictionary_offset = final_distance - max_distance - 1;
320            let ndbits = kBrotliDictionarySizeBitsByLength[copy_len] as usize;
321            let action = dictionary_offset >> ndbits;
322            let word_sub_index = dictionary_offset & ((1 << ndbits) - 1);
323            let word_index =
324                word_sub_index * copy_len + kBrotliDictionaryOffsetsByLength[copy_len] as usize;
325            let raw_word = &kBrotliDictionary[word_index..word_index + copy_len];
326            let mut transformed_word = [0u8; 38];
327            actual_copy_len = TransformDictionaryWord(
328                &mut transformed_word[..],
329                raw_word,
330                copy_len as i32,
331                action as i32,
332            ) as usize;
333            if actual_copy_len <= mb_len {
334                command_queue.push(interface::Command::Dict(interface::DictCommand {
335                    word_size: copy_len as u8,
336                    transform: action as u8,
337                    final_size: actual_copy_len as u8,
338                    empty: 0,
339                    word_id: word_sub_index as u32,
340                }));
341                mb_len -= actual_copy_len;
342                assert_eq!(
343                    InputPair(
344                        InputReference {
345                            data: transformed_word.split_at(actual_copy_len).0,
346                            orig_offset: 0
347                        },
348                        InputReference::default()
349                    ),
350                    interim.split_at(actual_copy_len).0
351                );
352            } else if mb_len != 0 {
353                // truncated dictionary word: represent it as literals instead
354                // won't be random noise since it fits in the dictionary, so we won't check for rand
355                command_queue.push_literals(&interim.split_at(mb_len).0);
356                mb_len = 0;
357                assert_eq!(
358                    InputPair(
359                        InputReference {
360                            data: transformed_word.split_at(mb_len).0,
361                            orig_offset: 0
362                        },
363                        InputReference::default()
364                    ),
365                    interim.split_at(mb_len).0
366                );
367            }
368        } else {
369            actual_copy_len = min(mb_len, copy_len);
370            if actual_copy_len != 0 {
371                command_queue.push(interface::Command::Copy(interface::CopyCommand {
372                    distance: final_distance as u32,
373                    num_bytes: actual_copy_len as u32,
374                }));
375            }
376            mb_len -= actual_copy_len;
377            if prev_dist_index != 1 || dist_offset != 0 {
378                // update distance cache unless it's the "0 distance symbol"
379                let mut tmp_dist_cache = [0i32; kNumDistanceCacheEntries - 1];
380                tmp_dist_cache.copy_from_slice(&local_dist_cache[..kNumDistanceCacheEntries - 1]);
381                local_dist_cache[1..].copy_from_slice(&tmp_dist_cache[..]);
382                local_dist_cache[0] = final_distance as i32;
383            }
384        }
385        {
386            btypec_sub -= 1;
387            if btypec_sub == 0 {
388                btypec_counter += 1;
389                if block_type.btypec.types.len() > btypec_counter {
390                    btypec_sub = block_type.btypec.lengths[btypec_counter];
391                    command_queue.push(interface::Command::BlockSwitchCommand(
392                        interface::BlockSwitch(block_type.btypec.types[btypec_counter]),
393                    ));
394                } else {
395                    btypec_sub = 1u32 << 31;
396                }
397            }
398        }
399        if copy_len != 0 && cmd.cmd_prefix_ >= 128 {
400            btyped_sub -= 1;
401            if btyped_sub == 0 {
402                btyped_counter += 1;
403                if block_type.btyped.types.len() > btyped_counter {
404                    btyped_sub = block_type.btyped.lengths[btyped_counter];
405                    command_queue.push(interface::Command::BlockSwitchDistance(
406                        interface::BlockSwitch(block_type.btyped.types[btyped_counter]),
407                    ));
408                } else {
409                    btyped_sub = 1u32 << 31;
410                }
411            }
412        }
413
414        let (copied, remainder) = interim.split_at(actual_copy_len);
415        recoder_state.num_bytes_encoded += copied.len();
416        input_iter = remainder;
417    }
418    recoder_state
419}
420
421#[cfg_attr(feature = "hotpath", hotpath::measure)]
422fn LogMetaBlock<'a, Alloc: BrotliAlloc, Cb>(
423    alloc: &mut Alloc,
424    commands: &[Command],
425    input0: &'a [u8],
426    input1: &'a [u8],
427    dist_cache: &[i32; kNumDistanceCacheEntries],
428    recoder_state: &mut RecoderState,
429    block_type: MetaBlockSplitRefs,
430    params: &BrotliEncoderParams,
431    context_type: Option<ContextType>,
432    callback: &mut Cb,
433) where
434    Cb: FnMut(
435        &mut interface::PredictionModeContextMap<InputReferenceMut>,
436        &mut [interface::StaticCommand],
437        InputPair,
438        &mut Alloc,
439    ),
440{
441    let mut local_literal_context_map = [0u8; 256 * 64];
442    let mut local_distance_context_map = [0u8; 256 * 64 + interface::DISTANCE_CONTEXT_MAP_OFFSET];
443    assert_eq!(
444        *block_type.btypel.types.iter().max().unwrap_or(&0) as u32 + 1,
445        block_type.btypel.num_types
446    );
447    assert_eq!(
448        *block_type.btypec.types.iter().max().unwrap_or(&0) as u32 + 1,
449        block_type.btypec.num_types
450    );
451    assert_eq!(
452        *block_type.btyped.types.iter().max().unwrap_or(&0) as u32 + 1,
453        block_type.btyped.num_types
454    );
455    if block_type.literal_context_map.len() <= 256 * 64 {
456        for (index, item) in block_type.literal_context_map.iter().enumerate() {
457            local_literal_context_map[index] = *item as u8;
458        }
459    }
460    if block_type.distance_context_map.len() <= 256 * 64 {
461        for (index, item) in block_type.distance_context_map.iter().enumerate() {
462            local_distance_context_map[interface::DISTANCE_CONTEXT_MAP_OFFSET + index] =
463                *item as u8;
464        }
465    }
466
467    let mut prediction_mode = interface::PredictionModeContextMap::<InputReferenceMut> {
468        literal_context_map: InputReferenceMut {
469            data: local_literal_context_map
470                .split_at_mut(block_type.literal_context_map.len())
471                .0,
472            orig_offset: 0,
473        },
474        predmode_speed_and_distance_context_map: InputReferenceMut {
475            data: local_distance_context_map
476                .split_at_mut(
477                    interface::PredictionModeContextMap::<InputReference>::size_of_combined_array(
478                        block_type.distance_context_map.len(),
479                    ),
480                )
481                .0,
482            orig_offset: 0,
483        },
484    };
485    for item in prediction_mode.get_mixing_values_mut().iter_mut() {
486        *item = prior_eval::WhichPrior::STRIDE1 as u8;
487    }
488    prediction_mode
489        .set_stride_context_speed([params.literal_adaptation[2], params.literal_adaptation[3]]);
490    prediction_mode
491        .set_context_map_speed([params.literal_adaptation[0], params.literal_adaptation[1]]);
492    prediction_mode.set_combined_stride_context_speed([
493        params.literal_adaptation[0],
494        params.literal_adaptation[1],
495    ]);
496
497    prediction_mode.set_literal_prediction_mode(interface::LiteralPredictionModeNibble(
498        context_type.unwrap_or(ContextType::CONTEXT_LSB6) as u8,
499    ));
500    let mut entropy_tally_scratch;
501    let mut entropy_pyramid;
502    if params.stride_detection_quality == 1 || params.stride_detection_quality == 2 {
503        entropy_tally_scratch = find_stride::EntropyTally::<Alloc>::new(alloc, None);
504        entropy_pyramid = find_stride::EntropyPyramid::<Alloc>::new(alloc);
505        entropy_pyramid.populate(input0, input1, &mut entropy_tally_scratch);
506    } else {
507        entropy_tally_scratch = find_stride::EntropyTally::<Alloc>::disabled_placeholder(alloc);
508        entropy_pyramid = find_stride::EntropyPyramid::<Alloc>::disabled_placeholder(alloc);
509    }
510    let input = InputPair(
511        InputReference {
512            data: input0,
513            orig_offset: 0,
514        },
515        InputReference {
516            data: input1,
517            orig_offset: input0.len(),
518        },
519    );
520    let mut best_strides = alloc_default::<u8, Alloc>();
521    if params.stride_detection_quality > 2 {
522        let mut stride_selector =
523            stride_eval::StrideEval::<Alloc>::new(alloc, input, &prediction_mode, params);
524        process_command_queue(
525            &mut stride_selector,
526            input,
527            commands,
528            dist_cache,
529            *recoder_state,
530            &block_type,
531            params,
532            context_type,
533        );
534        let ntypes = stride_selector.num_types();
535        best_strides = allocate::<u8, _>(stride_selector.alloc(), ntypes);
536        stride_selector.choose_stride(best_strides.slice_mut());
537    }
538    let mut context_map_entropy = ContextMapEntropy::<Alloc>::new(
539        alloc,
540        input,
541        entropy_pyramid.stride_last_level_range(),
542        prediction_mode,
543        params.cdf_adaptation_detection,
544    );
545    if params.cdf_adaptation_detection != 0 {
546        process_command_queue(
547            &mut context_map_entropy,
548            input,
549            commands,
550            dist_cache,
551            *recoder_state,
552            &block_type,
553            params,
554            context_type,
555        );
556        {
557            let (cm_speed, cm_cost) = context_map_entropy.best_singleton_speeds(true, false);
558            let (stride_speed, stride_cost) =
559                context_map_entropy.best_singleton_speeds(false, false);
560            let (combined_speed, combined_cost) =
561                context_map_entropy.best_singleton_speeds(false, true);
562            best_singleton_speed_log("CM", &cm_speed, &cm_cost);
563            best_singleton_speed_log("stride", &stride_speed, &stride_cost);
564            best_singleton_speed_log("combined", &combined_speed, &combined_cost);
565        }
566
567        let cm_speed = context_map_entropy.best_speeds(true, false);
568        let stride_speed = context_map_entropy.best_speeds(false, false);
569        let combined_speed = context_map_entropy.best_speeds(false, true);
570        let acost = context_map_entropy.best_speeds_costs(true, false);
571        let bcost = context_map_entropy.best_speeds_costs(false, false);
572        let ccost = context_map_entropy.best_speeds_costs(false, true);
573        context_map_entropy
574            .prediction_mode_mut()
575            .set_stride_context_speed(speed_to_tuple(stride_speed));
576        context_map_entropy
577            .prediction_mode_mut()
578            .set_context_map_speed(speed_to_tuple(cm_speed));
579        context_map_entropy
580            .prediction_mode_mut()
581            .set_combined_stride_context_speed(speed_to_tuple(combined_speed));
582
583        best_speed_log("CM", &cm_speed, &acost);
584        best_speed_log("Stride", &stride_speed, &bcost);
585        best_speed_log("StrideCombined", &combined_speed, &ccost);
586    }
587    let mut prior_selector = prior_eval::PriorEval::<Alloc>::new(
588        alloc,
589        input,
590        entropy_pyramid.stride_last_level_range(),
591        context_map_entropy.take_prediction_mode(),
592        params,
593    );
594    if params.prior_bitmask_detection != 0 {
595        process_command_queue(
596            &mut prior_selector,
597            input,
598            commands,
599            dist_cache,
600            *recoder_state,
601            &block_type,
602            params,
603            context_type,
604        );
605        prior_selector.choose_bitmask();
606    }
607    let prediction_mode = prior_selector.take_prediction_mode();
608    prior_selector.free(alloc);
609    let mut command_queue = CommandQueue::new(
610        alloc,
611        commands.len(),
612        prediction_mode,
613        input,
614        params.stride_detection_quality,
615        params.high_entropy_detection_quality,
616        context_map_entropy,
617        best_strides,
618        entropy_tally_scratch,
619        entropy_pyramid,
620    );
621
622    *recoder_state = process_command_queue(
623        &mut command_queue,
624        input,
625        commands,
626        dist_cache,
627        *recoder_state,
628        &block_type,
629        params,
630        context_type,
631    );
632    command_queue.free(callback).unwrap();
633    //   ::std::io::stderr().write(input0).unwrap();
634    //   ::std::io::stderr().write(input1).unwrap();
635}
636
637static kBlockLengthPrefixCode: [PrefixCodeRange; BROTLI_NUM_BLOCK_LEN_SYMBOLS] = [
638    PrefixCodeRange {
639        offset: 1u32,
640        nbits: 2u32,
641    },
642    PrefixCodeRange {
643        offset: 5u32,
644        nbits: 2u32,
645    },
646    PrefixCodeRange {
647        offset: 9u32,
648        nbits: 2u32,
649    },
650    PrefixCodeRange {
651        offset: 13u32,
652        nbits: 2u32,
653    },
654    PrefixCodeRange {
655        offset: 17u32,
656        nbits: 3u32,
657    },
658    PrefixCodeRange {
659        offset: 25u32,
660        nbits: 3u32,
661    },
662    PrefixCodeRange {
663        offset: 33u32,
664        nbits: 3u32,
665    },
666    PrefixCodeRange {
667        offset: 41u32,
668        nbits: 3u32,
669    },
670    PrefixCodeRange {
671        offset: 49u32,
672        nbits: 4u32,
673    },
674    PrefixCodeRange {
675        offset: 65u32,
676        nbits: 4u32,
677    },
678    PrefixCodeRange {
679        offset: 81u32,
680        nbits: 4u32,
681    },
682    PrefixCodeRange {
683        offset: 97u32,
684        nbits: 4u32,
685    },
686    PrefixCodeRange {
687        offset: 113u32,
688        nbits: 5u32,
689    },
690    PrefixCodeRange {
691        offset: 145u32,
692        nbits: 5u32,
693    },
694    PrefixCodeRange {
695        offset: 177u32,
696        nbits: 5u32,
697    },
698    PrefixCodeRange {
699        offset: 209u32,
700        nbits: 5u32,
701    },
702    PrefixCodeRange {
703        offset: 241u32,
704        nbits: 6u32,
705    },
706    PrefixCodeRange {
707        offset: 305u32,
708        nbits: 6u32,
709    },
710    PrefixCodeRange {
711        offset: 369u32,
712        nbits: 7u32,
713    },
714    PrefixCodeRange {
715        offset: 497u32,
716        nbits: 8u32,
717    },
718    PrefixCodeRange {
719        offset: 753u32,
720        nbits: 9u32,
721    },
722    PrefixCodeRange {
723        offset: 1265u32,
724        nbits: 10u32,
725    },
726    PrefixCodeRange {
727        offset: 2289u32,
728        nbits: 11u32,
729    },
730    PrefixCodeRange {
731        offset: 4337u32,
732        nbits: 12u32,
733    },
734    PrefixCodeRange {
735        offset: 8433u32,
736        nbits: 13u32,
737    },
738    PrefixCodeRange {
739        offset: 16625u32,
740        nbits: 24u32,
741    },
742];
743
744fn BrotliWriteBits(n_bits: u8, bits: u64, pos: &mut usize, array: &mut [u8]) {
745    assert_eq!(bits >> n_bits, 0);
746    assert!(n_bits <= 56);
747    let ptr_offset: usize = ((*pos >> 3) as u32) as usize;
748    let mut v = array[ptr_offset] as u64;
749    v |= bits << ((*pos) as u64 & 7);
750    array[ptr_offset + 7] = (v >> 56) as u8;
751    array[ptr_offset + 6] = ((v >> 48) & 0xff) as u8;
752    array[ptr_offset + 5] = ((v >> 40) & 0xff) as u8;
753    array[ptr_offset + 4] = ((v >> 32) & 0xff) as u8;
754    array[ptr_offset + 3] = ((v >> 24) & 0xff) as u8;
755    array[ptr_offset + 2] = ((v >> 16) & 0xff) as u8;
756    array[ptr_offset + 1] = ((v >> 8) & 0xff) as u8;
757    array[ptr_offset] = (v & 0xff) as u8;
758    *pos += n_bits as usize
759}
760
761fn BrotliWriteBitsPrepareStorage(pos: usize, array: &mut [u8]) {
762    assert_eq!(pos & 7, 0);
763    array[pos >> 3] = 0;
764}
765
766fn BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask(
767    num_codes: i32,
768    code_length_bitdepth: &[u8],
769    storage_ix: &mut usize,
770    storage: &mut [u8],
771) {
772    static kStorageOrder: [u8; 18] = [1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15];
773    static kHuffmanBitLengthHuffmanCodeSymbols: [u8; 6] = [0, 7, 3, 2, 1, 15];
774    static kHuffmanBitLengthHuffmanCodeBitLengths: [u8; 6] = [2, 4, 3, 2, 2, 4];
775    let mut skip_some: u64 = 0u64;
776    let mut codes_to_store: u64 = 18;
777    if num_codes > 1i32 {
778        while codes_to_store > 0 {
779            {
780                if code_length_bitdepth
781                    [(kStorageOrder[codes_to_store.wrapping_sub(1) as usize] as usize)]
782                    as i32
783                    != 0i32
784                {
785                    break;
786                }
787            }
788            codes_to_store = codes_to_store.wrapping_sub(1);
789        }
790    }
791    if code_length_bitdepth[(kStorageOrder[0] as usize)] as i32 == 0i32
792        && (code_length_bitdepth[(kStorageOrder[1] as usize)] as i32 == 0i32)
793    {
794        skip_some = 2;
795        if code_length_bitdepth[(kStorageOrder[2] as usize)] as i32 == 0i32 {
796            skip_some = 3;
797        }
798    }
799    BrotliWriteBits(2, skip_some, storage_ix, storage);
800
801    for i in skip_some..codes_to_store {
802        let l = code_length_bitdepth[kStorageOrder[i as usize] as usize] as usize;
803        BrotliWriteBits(
804            kHuffmanBitLengthHuffmanCodeBitLengths[l],
805            kHuffmanBitLengthHuffmanCodeSymbols[l] as u64,
806            storage_ix,
807            storage,
808        );
809    }
810}
811
812fn BrotliStoreHuffmanTreeToBitMask(
813    huffman_tree_size: usize,
814    huffman_tree: &[u8],
815    huffman_tree_extra_bits: &[u8],
816    code_length_bitdepth: &[u8],
817    code_length_bitdepth_symbols: &[u16],
818    storage_ix: &mut usize,
819    storage: &mut [u8],
820) {
821    for i in 0usize..huffman_tree_size {
822        let ix: usize = huffman_tree[i] as usize;
823        BrotliWriteBits(
824            code_length_bitdepth[ix],
825            code_length_bitdepth_symbols[ix] as (u64),
826            storage_ix,
827            storage,
828        );
829        if ix == 16usize {
830            BrotliWriteBits(2, huffman_tree_extra_bits[i] as (u64), storage_ix, storage);
831        } else if ix == 17usize {
832            BrotliWriteBits(3, huffman_tree_extra_bits[i] as (u64), storage_ix, storage);
833        }
834    }
835}
836
837pub fn BrotliStoreHuffmanTree(
838    depths: &[u8],
839    num: usize,
840    tree: &mut [HuffmanTree],
841    storage_ix: &mut usize,
842    storage: &mut [u8],
843) {
844    let mut huffman_tree = [0u8; 704];
845    let mut huffman_tree_extra_bits = [0u8; 704];
846    let mut huffman_tree_size = 0usize;
847    let mut code_length_bitdepth = [0u8; 18];
848    let mut code_length_bitdepth_symbols = [0u16; 18];
849    let mut huffman_tree_histogram = [0u32; 18];
850    let mut i: usize;
851    let mut num_codes: i32 = 0i32;
852    let mut code: usize = 0usize;
853
854    BrotliWriteHuffmanTree(
855        depths,
856        num,
857        &mut huffman_tree_size,
858        &mut huffman_tree[..],
859        &mut huffman_tree_extra_bits[..],
860    );
861    for i in 0usize..huffman_tree_size {
862        let _rhs = 1;
863        let _lhs = &mut huffman_tree_histogram[huffman_tree[i] as usize];
864        *_lhs = (*_lhs).wrapping_add(_rhs as u32);
865    }
866    i = 0usize;
867    while i < 18usize {
868        {
869            if huffman_tree_histogram[i] != 0 {
870                if num_codes == 0i32 {
871                    code = i;
872                    num_codes = 1i32;
873                } else if num_codes == 1i32 {
874                    num_codes = 2i32;
875                    {
876                        break;
877                    }
878                }
879            }
880        }
881        i = i.wrapping_add(1);
882    }
883    BrotliCreateHuffmanTree(
884        &mut huffman_tree_histogram,
885        18usize,
886        5i32,
887        tree,
888        &mut code_length_bitdepth,
889    );
890    BrotliConvertBitDepthsToSymbols(
891        &mut code_length_bitdepth,
892        18usize,
893        &mut code_length_bitdepth_symbols,
894    );
895    BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask(
896        num_codes,
897        &code_length_bitdepth,
898        storage_ix,
899        storage,
900    );
901    if num_codes == 1i32 {
902        code_length_bitdepth[code] = 0u8;
903    }
904    BrotliStoreHuffmanTreeToBitMask(
905        huffman_tree_size,
906        &huffman_tree,
907        &huffman_tree_extra_bits,
908        &code_length_bitdepth,
909        &code_length_bitdepth_symbols,
910        storage_ix,
911        storage,
912    );
913}
914
915fn StoreStaticCodeLengthCode(storage_ix: &mut usize, storage: &mut [u8]) {
916    BrotliWriteBits(40, 0xff_5555_5554, storage_ix, storage);
917}
918
919pub struct SimpleSortHuffmanTree {}
920
921impl HuffmanComparator for SimpleSortHuffmanTree {
922    fn Cmp(&self, v0: &HuffmanTree, v1: &HuffmanTree) -> bool {
923        v0.total_count_ < v1.total_count_
924    }
925}
926
927pub fn BrotliBuildAndStoreHuffmanTreeFast<AllocHT: alloc::Allocator<HuffmanTree>>(
928    m: &mut AllocHT,
929    histogram: &[u32],
930    histogram_total: usize,
931    max_bits: usize,
932    depth: &mut [u8],
933    bits: &mut [u16],
934    storage_ix: &mut usize,
935    storage: &mut [u8],
936) {
937    let mut count: u64 = 0;
938    let mut symbols: [u64; 4] = [0; 4];
939    let mut length: u64 = 0;
940    let mut total: usize = histogram_total;
941    while total != 0usize {
942        if histogram[(length as usize)] != 0 {
943            if count < 4 {
944                symbols[count as usize] = length;
945            }
946            count = count.wrapping_add(1);
947            total = total.wrapping_sub(histogram[(length as usize)] as usize);
948        }
949        length = length.wrapping_add(1);
950    }
951    if count <= 1 {
952        BrotliWriteBits(4, 1, storage_ix, storage);
953        BrotliWriteBits(max_bits as u8, symbols[0], storage_ix, storage);
954        depth[symbols[0] as usize] = 0u8;
955        bits[symbols[0] as usize] = 0u16;
956        return;
957    }
958    for depth_elem in depth[..(length as usize)].iter_mut() {
959        *depth_elem = 0; // memset
960    }
961    {
962        // FIXME: computation in u64, followed by allocation which might be less than u64
963        let max_tree_size: u64 = (2u64).wrapping_mul(length).wrapping_add(1);
964        // FIXME: makes little sense to test if N+1 > 0 -- always true unless wrapping. Perhaps use allocate() instead?
965        let mut tree = alloc_or_default::<HuffmanTree, _>(m, max_tree_size as usize);
966        let mut count_limit: u32;
967        count_limit = 1u32;
968        loop {
969            {
970                let mut node_index: u32 = 0u32;
971                let mut l: u64;
972                l = length;
973                while l != 0 {
974                    l = l.wrapping_sub(1);
975                    if histogram[l as usize] != 0 {
976                        if histogram[l as usize] >= count_limit {
977                            tree.slice_mut()[node_index as usize] =
978                                HuffmanTree::new(histogram[l as usize], -1, l as i16);
979                        } else {
980                            tree.slice_mut()[node_index as usize] =
981                                HuffmanTree::new(count_limit, -1, l as i16);
982                        }
983                        node_index = node_index.wrapping_add(1);
984                    }
985                }
986                {
987                    let n: i32 = node_index as i32;
988
989                    let mut i: i32 = 0i32;
990                    let mut j: i32 = n + 1i32;
991                    let mut k: i32;
992                    SortHuffmanTreeItems(tree.slice_mut(), n as usize, SimpleSortHuffmanTree {});
993                    let sentinel = HuffmanTree::new(u32::MAX, -1, -1);
994                    tree.slice_mut()[(node_index.wrapping_add(1) as usize)] = sentinel;
995                    tree.slice_mut()[(node_index as usize)] = sentinel;
996                    node_index = node_index.wrapping_add(2);
997                    k = n - 1i32;
998                    while k > 0i32 {
999                        {
1000                            let left: i32;
1001                            let right: i32;
1002                            if (tree.slice()[(i as usize)]).total_count_
1003                                <= (tree.slice()[(j as usize)]).total_count_
1004                            {
1005                                left = i;
1006                                i += 1;
1007                            } else {
1008                                left = j;
1009                                j += 1;
1010                            }
1011                            if (tree.slice()[(i as usize)]).total_count_
1012                                <= (tree.slice()[(j as usize)]).total_count_
1013                            {
1014                                right = i;
1015                                i += 1;
1016                            } else {
1017                                right = j;
1018                                j += 1;
1019                            }
1020                            let sum_total = (tree.slice()[(left as usize)])
1021                                .total_count_
1022                                .wrapping_add((tree.slice()[(right as usize)]).total_count_);
1023                            let tree_ind = (node_index.wrapping_sub(1) as usize);
1024                            (tree.slice_mut()[tree_ind]).total_count_ = sum_total;
1025                            (tree.slice_mut()[tree_ind]).index_left_ = left as i16;
1026                            (tree.slice_mut()[tree_ind]).index_right_or_value_ = right as i16;
1027                            tree.slice_mut()[(node_index as usize)] = sentinel;
1028                            node_index = node_index.wrapping_add(1);
1029                        }
1030                        k -= 1;
1031                    }
1032                    if BrotliSetDepth(2i32 * n - 1i32, tree.slice_mut(), depth, 14i32) {
1033                        break;
1034                    }
1035                }
1036            }
1037            count_limit = count_limit.wrapping_mul(2);
1038        }
1039        {
1040            m.free_cell(core::mem::take(&mut tree));
1041        }
1042    }
1043    BrotliConvertBitDepthsToSymbols(depth, length as usize, bits);
1044    if count <= 4 {
1045        BrotliWriteBits(2, 1, storage_ix, storage);
1046        BrotliWriteBits(2, count.wrapping_sub(1), storage_ix, storage);
1047        for i in 0..count as usize {
1048            for j in i + 1..count as usize {
1049                if depth[symbols[j] as usize] < depth[symbols[i] as usize] {
1050                    symbols.swap(j, i);
1051                }
1052            }
1053        }
1054        if count == 2 {
1055            BrotliWriteBits(max_bits as u8, symbols[0], storage_ix, storage);
1056            BrotliWriteBits(max_bits as u8, symbols[1], storage_ix, storage);
1057        } else if count == 3 {
1058            BrotliWriteBits(max_bits as u8, symbols[0], storage_ix, storage);
1059            BrotliWriteBits(max_bits as u8, symbols[1], storage_ix, storage);
1060            BrotliWriteBits(max_bits as u8, symbols[2], storage_ix, storage);
1061        } else {
1062            BrotliWriteBits(max_bits as u8, symbols[0], storage_ix, storage);
1063            BrotliWriteBits(max_bits as u8, symbols[1], storage_ix, storage);
1064            BrotliWriteBits(max_bits as u8, symbols[2], storage_ix, storage);
1065            BrotliWriteBits(max_bits as u8, symbols[3], storage_ix, storage);
1066            BrotliWriteBits(
1067                1,
1068                if depth[(symbols[0] as usize)] as i32 == 1i32 {
1069                    1i32
1070                } else {
1071                    0i32
1072                } as (u64),
1073                storage_ix,
1074                storage,
1075            );
1076        }
1077    } else {
1078        let mut previous_value: u8 = 8u8;
1079        let mut i: u64;
1080        StoreStaticCodeLengthCode(storage_ix, storage);
1081        i = 0;
1082        while i < length {
1083            let value: u8 = depth[(i as usize)];
1084            let mut reps: u64 = 1;
1085            let mut k: u64;
1086            k = i.wrapping_add(1);
1087            while k < length && (depth[(k as usize)] as i32 == value as i32) {
1088                {
1089                    reps = reps.wrapping_add(1);
1090                }
1091                k = k.wrapping_add(1);
1092            }
1093            i = i.wrapping_add(reps);
1094            if value as i32 == 0i32 {
1095                BrotliWriteBits(
1096                    kZeroRepsDepth[reps as usize] as u8,
1097                    kZeroRepsBits[reps as usize] as u64,
1098                    storage_ix,
1099                    storage,
1100                );
1101            } else {
1102                if previous_value as i32 != value as i32 {
1103                    BrotliWriteBits(
1104                        kCodeLengthDepth[value as usize],
1105                        kCodeLengthBits[value as usize] as (u64),
1106                        storage_ix,
1107                        storage,
1108                    );
1109                    reps = reps.wrapping_sub(1);
1110                }
1111                if reps < 3 {
1112                    while reps != 0 {
1113                        reps = reps.wrapping_sub(1);
1114                        BrotliWriteBits(
1115                            kCodeLengthDepth[value as usize],
1116                            kCodeLengthBits[value as usize] as (u64),
1117                            storage_ix,
1118                            storage,
1119                        );
1120                    }
1121                } else {
1122                    reps = reps.wrapping_sub(3);
1123                    BrotliWriteBits(
1124                        kNonZeroRepsDepth[reps as usize] as u8,
1125                        kNonZeroRepsBits[reps as usize] as u64,
1126                        storage_ix,
1127                        storage,
1128                    );
1129                }
1130                previous_value = value;
1131            }
1132        }
1133    }
1134}
1135
1136pub struct MetaBlockSplit<
1137    Alloc: alloc::Allocator<u8>
1138        + alloc::Allocator<u32>
1139        + alloc::Allocator<HistogramLiteral>
1140        + alloc::Allocator<HistogramCommand>
1141        + alloc::Allocator<HistogramDistance>,
1142> {
1143    pub literal_split: BlockSplit<Alloc>,
1144    pub command_split: BlockSplit<Alloc>,
1145    pub distance_split: BlockSplit<Alloc>,
1146    pub literal_context_map: <Alloc as Allocator<u32>>::AllocatedMemory,
1147    pub literal_context_map_size: usize,
1148    pub distance_context_map: <Alloc as Allocator<u32>>::AllocatedMemory,
1149    pub distance_context_map_size: usize,
1150    pub literal_histograms: <Alloc as Allocator<HistogramLiteral>>::AllocatedMemory,
1151    pub literal_histograms_size: usize,
1152    pub command_histograms: <Alloc as Allocator<HistogramCommand>>::AllocatedMemory,
1153    pub command_histograms_size: usize,
1154    pub distance_histograms: <Alloc as Allocator<HistogramDistance>>::AllocatedMemory,
1155    pub distance_histograms_size: usize,
1156}
1157impl<
1158    Alloc: alloc::Allocator<u8>
1159        + alloc::Allocator<u32>
1160        + alloc::Allocator<HistogramLiteral>
1161        + alloc::Allocator<HistogramCommand>
1162        + alloc::Allocator<HistogramDistance>,
1163> Default for MetaBlockSplit<Alloc>
1164{
1165    fn default() -> Self {
1166        Self {
1167            literal_split: BlockSplit::default(),
1168            command_split: BlockSplit::default(),
1169            distance_split: BlockSplit::default(),
1170            literal_context_map: alloc_default::<u32, Alloc>(),
1171            literal_context_map_size: 0,
1172            distance_context_map: alloc_default::<u32, Alloc>(),
1173            distance_context_map_size: 0,
1174            literal_histograms: alloc_default::<HistogramLiteral, Alloc>(),
1175            literal_histograms_size: 0,
1176            command_histograms: alloc_default::<HistogramCommand, Alloc>(),
1177            command_histograms_size: 0,
1178            distance_histograms: alloc_default::<HistogramDistance, Alloc>(),
1179            distance_histograms_size: 0,
1180        }
1181    }
1182}
1183
1184impl<
1185    Alloc: alloc::Allocator<u8>
1186        + alloc::Allocator<u32>
1187        + alloc::Allocator<HistogramLiteral>
1188        + alloc::Allocator<HistogramCommand>
1189        + alloc::Allocator<HistogramDistance>,
1190> MetaBlockSplit<Alloc>
1191{
1192    pub fn new() -> Self {
1193        Self::default()
1194    }
1195
1196    pub fn destroy(&mut self, alloc: &mut Alloc) {
1197        self.literal_split.destroy(alloc);
1198        self.command_split.destroy(alloc);
1199        self.distance_split.destroy(alloc);
1200        <Alloc as Allocator<u32>>::free_cell(alloc, core::mem::take(&mut self.literal_context_map));
1201        self.literal_context_map_size = 0;
1202        <Alloc as Allocator<u32>>::free_cell(
1203            alloc,
1204            core::mem::take(&mut self.distance_context_map),
1205        );
1206        self.distance_context_map_size = 0;
1207        <Alloc as Allocator<HistogramLiteral>>::free_cell(
1208            alloc,
1209            core::mem::take(&mut self.literal_histograms),
1210        );
1211
1212        self.literal_histograms_size = 0;
1213        <Alloc as Allocator<HistogramCommand>>::free_cell(
1214            alloc,
1215            core::mem::take(&mut self.command_histograms),
1216        );
1217        self.command_histograms_size = 0;
1218        <Alloc as Allocator<HistogramDistance>>::free_cell(
1219            alloc,
1220            core::mem::take(&mut self.distance_histograms),
1221        );
1222        self.distance_histograms_size = 0;
1223    }
1224}
1225#[derive(Clone, Copy)]
1226pub struct BlockTypeCodeCalculator {
1227    pub last_type: usize,
1228    pub second_last_type: usize,
1229}
1230
1231pub struct BlockSplitCode {
1232    pub type_code_calculator: BlockTypeCodeCalculator,
1233    pub type_depths: [u8; 258],
1234    pub type_bits: [u16; 258],
1235    pub length_depths: [u8; 26],
1236    pub length_bits: [u16; 26],
1237}
1238
1239pub struct BlockEncoder<'a, Alloc: alloc::Allocator<u8> + alloc::Allocator<u16>> {
1240    /*    pub alloc_u8 : AllocU8,
1241    pub alloc_u16 : AllocU16,
1242    pub alloc_u32 : AllocU32,
1243    pub alloc_ht : AllocHT,*/
1244    pub histogram_length_: usize,
1245    pub num_block_types_: usize,
1246    pub block_types_: &'a [u8],
1247    pub block_lengths_: &'a [u32],
1248    pub num_blocks_: usize,
1249    pub block_split_code_: BlockSplitCode,
1250    pub block_ix_: usize,
1251    pub block_len_: usize,
1252    pub entropy_ix_: usize,
1253    pub depths_: <Alloc as Allocator<u8>>::AllocatedMemory,
1254    pub bits_: <Alloc as Allocator<u16>>::AllocatedMemory,
1255}
1256
1257fn Log2FloorNonZero(mut n: u64) -> u32 {
1258    let mut result: u32 = 0u32;
1259    while n > 1 {
1260        n >>= 1;
1261        {
1262            result = result.wrapping_add(1);
1263        }
1264    }
1265    result
1266}
1267
1268fn BrotliEncodeMlen(length: u32, bits: &mut u64, numbits: &mut u32, nibblesbits: &mut u32) {
1269    let lg: u32 = (if length == 1u32 {
1270        1u32
1271    } else {
1272        Log2FloorNonZero(length.wrapping_sub(1) as (u64)).wrapping_add(1)
1273    });
1274    let mnibbles: u32 = (if lg < 16u32 {
1275        16u32
1276    } else {
1277        lg.wrapping_add(3)
1278    })
1279    .wrapping_div(4);
1280    assert!(length > 0);
1281    assert!(length <= (1 << 24));
1282    assert!(lg <= 24);
1283    *nibblesbits = mnibbles.wrapping_sub(4);
1284    *numbits = mnibbles.wrapping_mul(4);
1285    *bits = length.wrapping_sub(1) as u64;
1286}
1287
1288fn StoreCompressedMetaBlockHeader(
1289    is_final_block: bool,
1290    length: usize,
1291    storage_ix: &mut usize,
1292    storage: &mut [u8],
1293) {
1294    let mut lenbits: u64 = 0;
1295    let mut nlenbits: u32 = 0;
1296    let mut nibblesbits: u32 = 0;
1297    BrotliWriteBits(1, is_final_block.into(), storage_ix, storage);
1298    if is_final_block {
1299        BrotliWriteBits(1, 0, storage_ix, storage);
1300    }
1301    BrotliEncodeMlen(length as u32, &mut lenbits, &mut nlenbits, &mut nibblesbits);
1302    BrotliWriteBits(2, nibblesbits as u64, storage_ix, storage);
1303    BrotliWriteBits(nlenbits as u8, lenbits, storage_ix, storage);
1304    if !is_final_block {
1305        BrotliWriteBits(1, 0, storage_ix, storage);
1306    }
1307}
1308
1309impl BlockTypeCodeCalculator {
1310    fn new() -> Self {
1311        Self {
1312            last_type: 1,
1313            second_last_type: 0,
1314        }
1315    }
1316}
1317
1318impl<'a, Alloc: Allocator<u8> + Allocator<u16>> BlockEncoder<'a, Alloc> {
1319    fn new(
1320        histogram_length: usize,
1321        num_block_types: usize,
1322        block_types: &'a [u8],
1323        block_lengths: &'a [u32],
1324        num_blocks: usize,
1325    ) -> Self {
1326        let block_len = if num_blocks != 0 && !block_lengths.is_empty() {
1327            block_lengths[0] as usize
1328        } else {
1329            0
1330        };
1331        Self {
1332            histogram_length_: histogram_length,
1333            num_block_types_: num_block_types,
1334            block_types_: block_types,
1335            block_lengths_: block_lengths,
1336            num_blocks_: num_blocks,
1337            block_split_code_: BlockSplitCode {
1338                type_code_calculator: BlockTypeCodeCalculator::new(),
1339                type_depths: [0; 258],
1340                type_bits: [0; 258],
1341                length_depths: [0; 26],
1342                length_bits: [0; 26],
1343            },
1344            block_ix_: 0,
1345            block_len_: block_len,
1346            entropy_ix_: 0,
1347            depths_: alloc_default::<u8, Alloc>(),
1348            bits_: alloc_default::<u16, Alloc>(),
1349        }
1350    }
1351}
1352
1353fn NextBlockTypeCode(calculator: &mut BlockTypeCodeCalculator, type_: u8) -> usize {
1354    let type_code: usize = (if type_ as usize == calculator.last_type.wrapping_add(1) {
1355        1u32
1356    } else if type_ as usize == calculator.second_last_type {
1357        0u32
1358    } else {
1359        (type_ as u32).wrapping_add(2)
1360    }) as usize;
1361    calculator.second_last_type = calculator.last_type;
1362    calculator.last_type = type_ as usize;
1363    type_code
1364}
1365
1366fn BlockLengthPrefixCode(len: u32) -> u32 {
1367    let mut code: u32 = (if len >= 177u32 {
1368        if len >= 753u32 { 20i32 } else { 14i32 }
1369    } else if len >= 41u32 {
1370        7i32
1371    } else {
1372        0i32
1373    }) as u32;
1374    while code < (26i32 - 1i32) as u32
1375        && (len >= kBlockLengthPrefixCode[code.wrapping_add(1) as usize].offset)
1376    {
1377        code = code.wrapping_add(1);
1378    }
1379    code
1380}
1381
1382fn StoreVarLenUint8(n: u64, storage_ix: &mut usize, storage: &mut [u8]) {
1383    if n == 0 {
1384        BrotliWriteBits(1, 0, storage_ix, storage);
1385    } else {
1386        let nbits: u8 = Log2FloorNonZero(n) as u8;
1387        BrotliWriteBits(1, 1, storage_ix, storage);
1388        BrotliWriteBits(3, nbits as u64, storage_ix, storage);
1389        BrotliWriteBits(nbits, n.wrapping_sub(1u64 << nbits), storage_ix, storage);
1390    }
1391}
1392
1393fn StoreSimpleHuffmanTree(
1394    depths: &[u8],
1395    symbols: &mut [usize],
1396    num_symbols: usize,
1397    max_bits: usize,
1398    storage_ix: &mut usize,
1399    storage: &mut [u8],
1400) {
1401    BrotliWriteBits(2, 1, storage_ix, storage);
1402    BrotliWriteBits(2, num_symbols.wrapping_sub(1) as u64, storage_ix, storage);
1403    {
1404        for i in 0..num_symbols {
1405            for j in i + 1..num_symbols {
1406                if depths[symbols[j]] < depths[symbols[i]] {
1407                    symbols.swap(j, i);
1408                }
1409            }
1410        }
1411    }
1412    if num_symbols == 2usize {
1413        BrotliWriteBits(max_bits as u8, symbols[0] as u64, storage_ix, storage);
1414        BrotliWriteBits(max_bits as u8, symbols[1] as u64, storage_ix, storage);
1415    } else if num_symbols == 3usize {
1416        BrotliWriteBits(max_bits as u8, symbols[0] as u64, storage_ix, storage);
1417        BrotliWriteBits(max_bits as u8, symbols[1] as u64, storage_ix, storage);
1418        BrotliWriteBits(max_bits as u8, symbols[2] as u64, storage_ix, storage);
1419    } else {
1420        BrotliWriteBits(max_bits as u8, symbols[0] as u64, storage_ix, storage);
1421        BrotliWriteBits(max_bits as u8, symbols[1] as u64, storage_ix, storage);
1422        BrotliWriteBits(max_bits as u8, symbols[2] as u64, storage_ix, storage);
1423        BrotliWriteBits(max_bits as u8, symbols[3] as u64, storage_ix, storage);
1424        BrotliWriteBits(
1425            1,
1426            if depths[symbols[0]] as i32 == 1i32 {
1427                1i32
1428            } else {
1429                0i32
1430            } as (u64),
1431            storage_ix,
1432            storage,
1433        );
1434    }
1435}
1436
1437fn BuildAndStoreHuffmanTree(
1438    histogram: &[u32],
1439    histogram_length: usize,
1440    alphabet_size: usize,
1441    tree: &mut [HuffmanTree],
1442    depth: &mut [u8],
1443    bits: &mut [u16],
1444    storage_ix: &mut usize,
1445    storage: &mut [u8],
1446) {
1447    let mut count: usize = 0usize;
1448    let mut s4 = [0usize; 4];
1449    let mut i: usize;
1450    let mut max_bits: usize = 0usize;
1451    i = 0usize;
1452    while i < histogram_length {
1453        {
1454            if histogram[i] != 0 {
1455                if count < 4usize {
1456                    s4[count] = i;
1457                } else if count > 4usize {
1458                    break;
1459                }
1460                count = count.wrapping_add(1);
1461            }
1462        }
1463        i = i.wrapping_add(1);
1464    }
1465    {
1466        let mut max_bits_counter: usize = alphabet_size.wrapping_sub(1);
1467        while max_bits_counter != 0 {
1468            max_bits_counter >>= 1i32;
1469            max_bits = max_bits.wrapping_add(1);
1470        }
1471    }
1472    if count <= 1 {
1473        BrotliWriteBits(4, 1, storage_ix, storage);
1474        BrotliWriteBits(max_bits as u8, s4[0] as u64, storage_ix, storage);
1475        depth[s4[0]] = 0u8;
1476        bits[s4[0]] = 0u16;
1477        return;
1478    }
1479
1480    for depth_elem in depth[..histogram_length].iter_mut() {
1481        *depth_elem = 0; // memset
1482    }
1483    BrotliCreateHuffmanTree(histogram, histogram_length, 15i32, tree, depth);
1484    BrotliConvertBitDepthsToSymbols(depth, histogram_length, bits);
1485    if count <= 4usize {
1486        StoreSimpleHuffmanTree(depth, &mut s4[..], count, max_bits, storage_ix, storage);
1487    } else {
1488        BrotliStoreHuffmanTree(depth, histogram_length, tree, storage_ix, storage);
1489    }
1490}
1491
1492fn GetBlockLengthPrefixCode(len: u32, code: &mut usize, n_extra: &mut u32, extra: &mut u32) {
1493    *code = BlockLengthPrefixCode(len) as usize;
1494    *n_extra = kBlockLengthPrefixCode[*code].nbits;
1495    *extra = len.wrapping_sub(kBlockLengthPrefixCode[*code].offset);
1496}
1497
1498fn StoreBlockSwitch(
1499    code: &mut BlockSplitCode,
1500    block_len: u32,
1501    block_type: u8,
1502    is_first_block: bool,
1503    storage_ix: &mut usize,
1504    storage: &mut [u8],
1505) {
1506    let typecode: usize = NextBlockTypeCode(&mut code.type_code_calculator, block_type);
1507    let mut lencode: usize = 0;
1508    let mut len_nextra: u32 = 0;
1509    let mut len_extra: u32 = 0;
1510    if !is_first_block {
1511        BrotliWriteBits(
1512            code.type_depths[typecode] as u8,
1513            code.type_bits[typecode] as (u64),
1514            storage_ix,
1515            storage,
1516        );
1517    }
1518    GetBlockLengthPrefixCode(block_len, &mut lencode, &mut len_nextra, &mut len_extra);
1519    BrotliWriteBits(
1520        code.length_depths[lencode],
1521        code.length_bits[lencode] as (u64),
1522        storage_ix,
1523        storage,
1524    );
1525    BrotliWriteBits(len_nextra as u8, len_extra as (u64), storage_ix, storage);
1526}
1527
1528fn BuildAndStoreBlockSplitCode(
1529    types: &[u8],
1530    lengths: &[u32],
1531    num_blocks: usize,
1532    num_types: usize,
1533    tree: &mut [HuffmanTree],
1534    code: &mut BlockSplitCode,
1535    storage_ix: &mut usize,
1536    storage: &mut [u8],
1537) {
1538    let mut type_histo: [u32; 258] = [0; 258];
1539    let mut length_histo: [u32; 26] = [0; 26];
1540    let mut i: usize;
1541    let mut type_code_calculator = BlockTypeCodeCalculator::new();
1542    i = 0usize;
1543    while i < num_blocks {
1544        {
1545            let type_code: usize = NextBlockTypeCode(&mut type_code_calculator, types[i]);
1546            if i != 0usize {
1547                let _rhs = 1;
1548                let _lhs = &mut type_histo[type_code];
1549                *_lhs = (*_lhs).wrapping_add(_rhs as u32);
1550            }
1551            {
1552                let _rhs = 1;
1553                let _lhs = &mut length_histo[BlockLengthPrefixCode(lengths[i]) as usize];
1554                *_lhs = (*_lhs).wrapping_add(_rhs as u32);
1555            }
1556        }
1557        i = i.wrapping_add(1);
1558    }
1559    StoreVarLenUint8(num_types.wrapping_sub(1) as u64, storage_ix, storage);
1560    if num_types > 1 {
1561        BuildAndStoreHuffmanTree(
1562            &mut type_histo[0..],
1563            num_types.wrapping_add(2),
1564            num_types.wrapping_add(2),
1565            tree,
1566            &mut code.type_depths[0..],
1567            &mut code.type_bits[0..],
1568            storage_ix,
1569            storage,
1570        );
1571        BuildAndStoreHuffmanTree(
1572            &mut length_histo[0..],
1573            super::constants::BROTLI_NUM_BLOCK_LEN_SYMBOLS, // 26
1574            super::constants::BROTLI_NUM_BLOCK_LEN_SYMBOLS,
1575            tree,
1576            &mut code.length_depths[0..],
1577            &mut code.length_bits[0..],
1578            storage_ix,
1579            storage,
1580        );
1581        StoreBlockSwitch(code, lengths[0], types[0], true, storage_ix, storage);
1582    }
1583}
1584
1585impl<Alloc: Allocator<u8> + Allocator<u16>> BlockEncoder<'_, Alloc> {
1586    fn build_and_store_block_switch_entropy_codes(
1587        &mut self,
1588        tree: &mut [HuffmanTree],
1589        storage_ix: &mut usize,
1590        storage: &mut [u8],
1591    ) {
1592        BuildAndStoreBlockSplitCode(
1593            self.block_types_,
1594            self.block_lengths_,
1595            self.num_blocks_,
1596            self.num_block_types_,
1597            tree,
1598            &mut self.block_split_code_,
1599            storage_ix,
1600            storage,
1601        );
1602    }
1603}
1604
1605fn StoreTrivialContextMap(
1606    num_types: usize,
1607    context_bits: usize,
1608    tree: &mut [HuffmanTree],
1609    storage_ix: &mut usize,
1610    storage: &mut [u8],
1611) {
1612    StoreVarLenUint8(num_types.wrapping_sub(1) as u64, storage_ix, storage);
1613    if num_types > 1 {
1614        let repeat_code: usize = context_bits.wrapping_sub(1u32 as usize);
1615        let repeat_bits: usize = (1u32 << repeat_code).wrapping_sub(1) as usize;
1616        let alphabet_size: usize = num_types.wrapping_add(repeat_code);
1617        let mut histogram: [u32; 272] = [0; 272];
1618        let mut depths: [u8; 272] = [0; 272];
1619        let mut bits: [u16; 272] = [0; 272];
1620        BrotliWriteBits(1u8, 1u64, storage_ix, storage);
1621        BrotliWriteBits(4u8, repeat_code.wrapping_sub(1) as u64, storage_ix, storage);
1622        histogram[repeat_code] = num_types as u32;
1623        histogram[0] = 1;
1624        for i in context_bits..alphabet_size {
1625            histogram[i] = 1;
1626        }
1627        BuildAndStoreHuffmanTree(
1628            &mut histogram[..],
1629            alphabet_size,
1630            alphabet_size,
1631            tree,
1632            &mut depths[..],
1633            &mut bits[..],
1634            storage_ix,
1635            storage,
1636        );
1637        for i in 0usize..num_types {
1638            let code: usize = if i == 0usize {
1639                0usize
1640            } else {
1641                i.wrapping_add(context_bits).wrapping_sub(1)
1642            };
1643            BrotliWriteBits(depths[code], bits[code] as (u64), storage_ix, storage);
1644            BrotliWriteBits(
1645                depths[repeat_code],
1646                bits[repeat_code] as (u64),
1647                storage_ix,
1648                storage,
1649            );
1650            BrotliWriteBits(repeat_code as u8, repeat_bits as u64, storage_ix, storage);
1651        }
1652        BrotliWriteBits(1, 1, storage_ix, storage);
1653    }
1654}
1655
1656fn IndexOf(v: &[u8], v_size: usize, value: u8) -> usize {
1657    let mut i: usize = 0usize;
1658    while i < v_size {
1659        {
1660            if v[i] as i32 == value as i32 {
1661                return i;
1662            }
1663        }
1664        i = i.wrapping_add(1);
1665    }
1666    i
1667}
1668
1669fn MoveToFront(v: &mut [u8], index: usize) {
1670    let value: u8 = v[index];
1671    let mut i: usize;
1672    i = index;
1673    while i != 0usize {
1674        {
1675            v[i] = v[i.wrapping_sub(1)];
1676        }
1677        i = i.wrapping_sub(1);
1678    }
1679    v[0] = value;
1680}
1681
1682fn MoveToFrontTransform(v_in: &[u32], v_size: usize, v_out: &mut [u32]) {
1683    let mut mtf: [u8; 256] = [0; 256];
1684    let mut max_value: u32;
1685    if v_size == 0usize {
1686        return;
1687    }
1688    max_value = v_in[0];
1689    for i in 1..v_size {
1690        if v_in[i] > max_value {
1691            max_value = v_in[i];
1692        }
1693    }
1694    for i in 0..=max_value as usize {
1695        mtf[i] = i as u8;
1696    }
1697    {
1698        let mtf_size: usize = max_value.wrapping_add(1) as usize;
1699        for i in 0usize..v_size {
1700            let index: usize = IndexOf(&mtf[..], mtf_size, v_in[i] as u8);
1701            v_out[i] = index as u32;
1702            MoveToFront(&mut mtf[..], index);
1703        }
1704    }
1705}
1706
1707fn RunLengthCodeZeros(
1708    in_size: usize,
1709    v: &mut [u32],
1710    out_size: &mut usize,
1711    max_run_length_prefix: &mut u32,
1712) {
1713    let mut max_reps: u32 = 0u32;
1714    let mut i: usize;
1715    let mut max_prefix: u32;
1716    i = 0usize;
1717    while i < in_size {
1718        let mut reps: u32 = 0u32;
1719        while i < in_size && (v[i] != 0u32) {
1720            i = i.wrapping_add(1);
1721        }
1722        while i < in_size && (v[i] == 0u32) {
1723            {
1724                reps = reps.wrapping_add(1);
1725            }
1726            i = i.wrapping_add(1);
1727        }
1728        max_reps = max(reps, max_reps);
1729    }
1730    max_prefix = if max_reps > 0u32 {
1731        Log2FloorNonZero(max_reps as (u64))
1732    } else {
1733        0u32
1734    };
1735    max_prefix = min(max_prefix, *max_run_length_prefix);
1736    *max_run_length_prefix = max_prefix;
1737    *out_size = 0usize;
1738    i = 0usize;
1739    while i < in_size {
1740        if v[i] != 0u32 {
1741            v[*out_size] = (v[i]).wrapping_add(*max_run_length_prefix);
1742            i = i.wrapping_add(1);
1743            *out_size = out_size.wrapping_add(1);
1744        } else {
1745            let mut reps: u32 = 1u32;
1746            let mut k: usize;
1747            k = i.wrapping_add(1);
1748            while k < in_size && (v[k] == 0u32) {
1749                {
1750                    reps = reps.wrapping_add(1);
1751                }
1752                k = k.wrapping_add(1);
1753            }
1754            i = i.wrapping_add(reps as usize);
1755            while reps != 0u32 {
1756                if reps < 2u32 << max_prefix {
1757                    let run_length_prefix: u32 = Log2FloorNonZero(reps as (u64));
1758                    let extra_bits: u32 = reps.wrapping_sub(1u32 << run_length_prefix);
1759                    v[*out_size] = run_length_prefix.wrapping_add(extra_bits << 9);
1760                    *out_size = out_size.wrapping_add(1);
1761                    {
1762                        break;
1763                    }
1764                } else {
1765                    let extra_bits: u32 = (1u32 << max_prefix).wrapping_sub(1);
1766                    v[*out_size] = max_prefix.wrapping_add(extra_bits << 9);
1767                    reps = reps.wrapping_sub((2u32 << max_prefix).wrapping_sub(1));
1768                    *out_size = out_size.wrapping_add(1);
1769                }
1770            }
1771        }
1772    }
1773}
1774
1775fn EncodeContextMap<AllocU32: alloc::Allocator<u32>>(
1776    m: &mut AllocU32,
1777    context_map: &[u32],
1778    context_map_size: usize,
1779    num_clusters: usize,
1780    tree: &mut [HuffmanTree],
1781    storage_ix: &mut usize,
1782    storage: &mut [u8],
1783) {
1784    let mut rle_symbols: AllocU32::AllocatedMemory;
1785    let mut max_run_length_prefix: u32 = 6u32;
1786    let mut num_rle_symbols: usize = 0usize;
1787    static kSymbolMask: u32 = (1u32 << 9) - 1;
1788    let mut depths: [u8; 272] = [0; 272];
1789    let mut bits: [u16; 272] = [0; 272];
1790    StoreVarLenUint8(num_clusters.wrapping_sub(1) as u64, storage_ix, storage);
1791    if num_clusters == 1 {
1792        return;
1793    }
1794    rle_symbols = alloc_or_default::<u32, _>(m, context_map_size);
1795    MoveToFrontTransform(context_map, context_map_size, rle_symbols.slice_mut());
1796    RunLengthCodeZeros(
1797        context_map_size,
1798        rle_symbols.slice_mut(),
1799        &mut num_rle_symbols,
1800        &mut max_run_length_prefix,
1801    );
1802    let mut histogram: [u32; 272] = [0; 272];
1803    for i in 0usize..num_rle_symbols {
1804        let _rhs = 1;
1805        let _lhs = &mut histogram[(rle_symbols.slice()[i] & kSymbolMask) as usize];
1806        *_lhs = (*_lhs).wrapping_add(_rhs as u32);
1807    }
1808    {
1809        let use_rle = max_run_length_prefix > 0;
1810        BrotliWriteBits(1, u64::from(use_rle), storage_ix, storage);
1811        if use_rle {
1812            BrotliWriteBits(
1813                4,
1814                max_run_length_prefix.wrapping_sub(1) as (u64),
1815                storage_ix,
1816                storage,
1817            );
1818        }
1819    }
1820    BuildAndStoreHuffmanTree(
1821        &mut histogram[..],
1822        num_clusters.wrapping_add(max_run_length_prefix as usize),
1823        num_clusters.wrapping_add(max_run_length_prefix as usize),
1824        tree,
1825        &mut depths[..],
1826        &mut bits[..],
1827        storage_ix,
1828        storage,
1829    );
1830    for i in 0usize..num_rle_symbols {
1831        let rle_symbol: u32 = rle_symbols.slice()[i] & kSymbolMask;
1832        let extra_bits_val: u32 = rle_symbols.slice()[i] >> 9;
1833        BrotliWriteBits(
1834            depths[rle_symbol as usize],
1835            bits[rle_symbol as usize] as (u64),
1836            storage_ix,
1837            storage,
1838        );
1839        if rle_symbol > 0u32 && (rle_symbol <= max_run_length_prefix) {
1840            BrotliWriteBits(
1841                rle_symbol as u8,
1842                extra_bits_val as (u64),
1843                storage_ix,
1844                storage,
1845            );
1846        }
1847    }
1848    BrotliWriteBits(1, 1, storage_ix, storage);
1849    m.free_cell(rle_symbols);
1850}
1851
1852impl<Alloc: Allocator<u8> + Allocator<u16>> BlockEncoder<'_, Alloc> {
1853    fn build_and_store_entropy_codes<HistogramType: SliceWrapper<u32>>(
1854        &mut self,
1855        m: &mut Alloc,
1856        histograms: &[HistogramType],
1857        histograms_size: usize,
1858        alphabet_size: usize,
1859        tree: &mut [HuffmanTree],
1860        storage_ix: &mut usize,
1861        storage: &mut [u8],
1862    ) {
1863        let table_size: usize = histograms_size.wrapping_mul(self.histogram_length_);
1864        self.depths_ = alloc_or_default::<u8, _>(m, table_size);
1865        self.bits_ = alloc_or_default::<u16, _>(m, table_size);
1866        {
1867            for i in 0usize..histograms_size {
1868                let ix: usize = i.wrapping_mul(self.histogram_length_);
1869                BuildAndStoreHuffmanTree(
1870                    &(histograms[i]).slice()[0..],
1871                    self.histogram_length_,
1872                    alphabet_size,
1873                    tree,
1874                    &mut self.depths_.slice_mut()[ix..],
1875                    &mut self.bits_.slice_mut()[ix..],
1876                    storage_ix,
1877                    storage,
1878                );
1879            }
1880        }
1881    }
1882
1883    fn store_symbol(&mut self, symbol: usize, storage_ix: &mut usize, storage: &mut [u8]) {
1884        if self.block_len_ == 0usize {
1885            let block_ix: usize = {
1886                self.block_ix_ = self.block_ix_.wrapping_add(1);
1887                self.block_ix_
1888            };
1889            let block_len: u32 = self.block_lengths_[block_ix];
1890            let block_type: u8 = self.block_types_[block_ix];
1891            self.block_len_ = block_len as usize;
1892            self.entropy_ix_ = (block_type as usize).wrapping_mul(self.histogram_length_);
1893            StoreBlockSwitch(
1894                &mut self.block_split_code_,
1895                block_len,
1896                block_type,
1897                false,
1898                storage_ix,
1899                storage,
1900            );
1901        }
1902        self.block_len_ = self.block_len_.wrapping_sub(1);
1903        {
1904            let ix: usize = self.entropy_ix_.wrapping_add(symbol);
1905            BrotliWriteBits(
1906                self.depths_.slice()[ix],
1907                self.bits_.slice()[ix] as (u64),
1908                storage_ix,
1909                storage,
1910            );
1911        }
1912    }
1913}
1914
1915impl Command {
1916    fn copy_len_code(&self) -> u32 {
1917        let modifier = self.copy_len_ >> 25;
1918        let delta: i32 = ((modifier | ((modifier & 0x40) << 1)) as u8) as i8 as i32;
1919        ((self.copy_len_ & 0x01ff_ffff) as i32 + delta) as u32
1920    }
1921}
1922
1923fn GetInsertExtra(inscode: u16) -> u32 {
1924    kInsExtra[inscode as usize]
1925}
1926
1927fn GetInsertBase(inscode: u16) -> u32 {
1928    kInsBase[inscode as usize]
1929}
1930
1931fn GetCopyBase(copycode: u16) -> u32 {
1932    kCopyBase[copycode as usize]
1933}
1934
1935fn GetCopyExtra(copycode: u16) -> u32 {
1936    kCopyExtra[copycode as usize]
1937}
1938
1939fn StoreCommandExtra(cmd: &Command, storage_ix: &mut usize, storage: &mut [u8]) {
1940    let copylen_code = cmd.copy_len_code();
1941    let inscode: u16 = GetInsertLengthCode(cmd.insert_len_ as usize);
1942    let copycode: u16 = GetCopyLengthCode(copylen_code as usize);
1943    let insnumextra: u32 = GetInsertExtra(inscode);
1944    let insextraval: u64 = cmd.insert_len_.wrapping_sub(GetInsertBase(inscode)) as (u64);
1945    let copyextraval: u64 = copylen_code.wrapping_sub(GetCopyBase(copycode)) as (u64);
1946    let bits: u64 = copyextraval << insnumextra | insextraval;
1947    BrotliWriteBits(
1948        insnumextra.wrapping_add(GetCopyExtra(copycode)) as u8,
1949        bits,
1950        storage_ix,
1951        storage,
1952    );
1953}
1954
1955fn Context(p1: u8, p2: u8, mode: ContextType) -> u8 {
1956    match mode {
1957        ContextType::CONTEXT_LSB6 => (p1 as i32 & 0x3fi32) as u8,
1958        ContextType::CONTEXT_MSB6 => (p1 as i32 >> 2) as u8,
1959        ContextType::CONTEXT_UTF8 => {
1960            (kUTF8ContextLookup[p1 as usize] as i32
1961                | kUTF8ContextLookup[(p2 as i32 + 256i32) as usize] as i32) as u8
1962        }
1963        ContextType::CONTEXT_SIGNED => {
1964            (((kSigned3BitContextLookup[p1 as usize] as i32) << 3)
1965                + kSigned3BitContextLookup[p2 as usize] as i32) as u8
1966        }
1967    }
1968    //  0u8
1969}
1970
1971impl<Alloc: Allocator<u8> + Allocator<u16>> BlockEncoder<'_, Alloc> {
1972    fn store_symbol_with_context(
1973        &mut self,
1974        symbol: usize,
1975        context: usize,
1976        context_map: &[u32],
1977        storage_ix: &mut usize,
1978        storage: &mut [u8],
1979        context_bits: usize,
1980    ) {
1981        if self.block_len_ == 0 {
1982            let block_ix: usize = {
1983                self.block_ix_ = self.block_ix_.wrapping_add(1);
1984                self.block_ix_
1985            };
1986            let block_len: u32 = self.block_lengths_[block_ix];
1987            let block_type: u8 = self.block_types_[block_ix];
1988            self.block_len_ = block_len as usize;
1989            self.entropy_ix_ = (block_type as usize) << context_bits;
1990            StoreBlockSwitch(
1991                &mut self.block_split_code_,
1992                block_len,
1993                block_type,
1994                false,
1995                storage_ix,
1996                storage,
1997            );
1998        }
1999        self.block_len_ = self.block_len_.wrapping_sub(1);
2000        {
2001            let histo_ix: usize = context_map[self.entropy_ix_.wrapping_add(context)] as usize;
2002            let ix: usize = histo_ix
2003                .wrapping_mul(self.histogram_length_)
2004                .wrapping_add(symbol);
2005            BrotliWriteBits(
2006                self.depths_.slice()[ix],
2007                self.bits_.slice()[ix] as (u64),
2008                storage_ix,
2009                storage,
2010            );
2011        }
2012    }
2013}
2014
2015impl<Alloc: Allocator<u8> + Allocator<u16>> BlockEncoder<'_, Alloc> {
2016    fn cleanup(&mut self, m: &mut Alloc) {
2017        <Alloc as Allocator<u8>>::free_cell(m, core::mem::take(&mut self.depths_));
2018        <Alloc as Allocator<u16>>::free_cell(m, core::mem::take(&mut self.bits_));
2019    }
2020}
2021
2022pub fn JumpToByteBoundary(storage_ix: &mut usize, storage: &mut [u8]) {
2023    *storage_ix = storage_ix.wrapping_add(7u32 as usize) & !7u32 as usize;
2024    storage[(*storage_ix >> 3)] = 0u8;
2025}
2026
2027#[cfg_attr(feature = "hotpath", hotpath::measure)]
2028pub(crate) fn store_meta_block<Alloc: BrotliAlloc, Cb>(
2029    alloc: &mut Alloc,
2030    input: &[u8],
2031    start_pos: usize,
2032    length: usize,
2033    mask: usize,
2034    mut prev_byte: u8,
2035    mut prev_byte2: u8,
2036    is_last: bool,
2037    params: &BrotliEncoderParams,
2038    literal_context_mode: ContextType,
2039    distance_cache: &[i32; kNumDistanceCacheEntries],
2040    commands: &[Command],
2041    n_commands: usize,
2042    mb: &mut MetaBlockSplit<Alloc>,
2043    recoder_state: &mut RecoderState,
2044    storage_ix: &mut usize,
2045    storage: &mut [u8],
2046    callback: &mut Cb,
2047) where
2048    Cb: FnMut(
2049        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2050        &mut [interface::StaticCommand],
2051        InputPair,
2052        &mut Alloc,
2053    ),
2054{
2055    let (input0, input1) = InputPairFromMaskedInput(input, start_pos, length, mask);
2056    if params.log_meta_block {
2057        LogMetaBlock(
2058            alloc,
2059            commands.split_at(n_commands).0,
2060            input0,
2061            input1,
2062            distance_cache,
2063            recoder_state,
2064            block_split_reference(mb),
2065            params,
2066            Some(literal_context_mode),
2067            callback,
2068        );
2069    }
2070    let mut pos: usize = start_pos;
2071    let num_distance_symbols = params.dist.alphabet_size;
2072    let mut num_effective_distance_symbols = num_distance_symbols as usize;
2073    let _literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
2074    let mut literal_enc: BlockEncoder<Alloc>;
2075    let mut command_enc: BlockEncoder<Alloc>;
2076    let mut distance_enc: BlockEncoder<Alloc>;
2077    let dist = &params.dist;
2078    if params.large_window && num_effective_distance_symbols > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS
2079    {
2080        num_effective_distance_symbols = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
2081    }
2082    StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
2083    let mut tree = allocate::<HuffmanTree, _>(alloc, 2 * 704 + 1);
2084    literal_enc = BlockEncoder::new(
2085        BROTLI_NUM_LITERAL_SYMBOLS,
2086        mb.literal_split.num_types,
2087        mb.literal_split.types.slice(),
2088        mb.literal_split.lengths.slice(),
2089        mb.literal_split.num_blocks,
2090    );
2091    command_enc = BlockEncoder::new(
2092        BROTLI_NUM_COMMAND_SYMBOLS,
2093        mb.command_split.num_types,
2094        mb.command_split.types.slice(),
2095        mb.command_split.lengths.slice(),
2096        mb.command_split.num_blocks,
2097    );
2098    distance_enc = BlockEncoder::new(
2099        num_effective_distance_symbols,
2100        mb.distance_split.num_types,
2101        mb.distance_split.types.slice(),
2102        mb.distance_split.lengths.slice(),
2103        mb.distance_split.num_blocks,
2104    );
2105    literal_enc.build_and_store_block_switch_entropy_codes(tree.slice_mut(), storage_ix, storage);
2106    command_enc.build_and_store_block_switch_entropy_codes(tree.slice_mut(), storage_ix, storage);
2107    distance_enc.build_and_store_block_switch_entropy_codes(tree.slice_mut(), storage_ix, storage);
2108    BrotliWriteBits(2, dist.distance_postfix_bits as (u64), storage_ix, storage);
2109    BrotliWriteBits(
2110        4,
2111        (dist.num_direct_distance_codes >> dist.distance_postfix_bits) as (u64),
2112        storage_ix,
2113        storage,
2114    );
2115    for _i in 0usize..mb.literal_split.num_types {
2116        BrotliWriteBits(2, literal_context_mode as (u64), storage_ix, storage);
2117    }
2118    if mb.literal_context_map_size == 0usize {
2119        StoreTrivialContextMap(
2120            mb.literal_histograms_size,
2121            6,
2122            tree.slice_mut(),
2123            storage_ix,
2124            storage,
2125        );
2126    } else {
2127        EncodeContextMap(
2128            alloc,
2129            mb.literal_context_map.slice(),
2130            mb.literal_context_map_size,
2131            mb.literal_histograms_size,
2132            tree.slice_mut(),
2133            storage_ix,
2134            storage,
2135        );
2136    }
2137    if mb.distance_context_map_size == 0usize {
2138        StoreTrivialContextMap(
2139            mb.distance_histograms_size,
2140            2usize,
2141            tree.slice_mut(),
2142            storage_ix,
2143            storage,
2144        );
2145    } else {
2146        EncodeContextMap(
2147            alloc,
2148            mb.distance_context_map.slice(),
2149            mb.distance_context_map_size,
2150            mb.distance_histograms_size,
2151            tree.slice_mut(),
2152            storage_ix,
2153            storage,
2154        );
2155    }
2156    literal_enc.build_and_store_entropy_codes(
2157        alloc,
2158        mb.literal_histograms.slice(),
2159        mb.literal_histograms_size,
2160        BROTLI_NUM_LITERAL_SYMBOLS,
2161        tree.slice_mut(),
2162        storage_ix,
2163        storage,
2164    );
2165    command_enc.build_and_store_entropy_codes(
2166        alloc,
2167        mb.command_histograms.slice(),
2168        mb.command_histograms_size,
2169        BROTLI_NUM_COMMAND_SYMBOLS,
2170        tree.slice_mut(),
2171        storage_ix,
2172        storage,
2173    );
2174    distance_enc.build_and_store_entropy_codes(
2175        alloc,
2176        mb.distance_histograms.slice(),
2177        mb.distance_histograms_size,
2178        num_distance_symbols as usize,
2179        tree.slice_mut(),
2180        storage_ix,
2181        storage,
2182    );
2183    {
2184        <Alloc as Allocator<HuffmanTree>>::free_cell(alloc, core::mem::take(&mut tree));
2185    }
2186    for i in 0usize..n_commands {
2187        let cmd: Command = commands[i];
2188        let cmd_code: usize = cmd.cmd_prefix_ as usize;
2189        command_enc.store_symbol(cmd_code, storage_ix, storage);
2190        StoreCommandExtra(&cmd, storage_ix, storage);
2191        if mb.literal_context_map_size == 0usize {
2192            let mut j: usize;
2193            j = cmd.insert_len_ as usize;
2194            while j != 0usize {
2195                {
2196                    literal_enc.store_symbol(input[(pos & mask)] as usize, storage_ix, storage);
2197                    pos = pos.wrapping_add(1);
2198                }
2199                j = j.wrapping_sub(1);
2200            }
2201        } else {
2202            let mut j: usize;
2203            j = cmd.insert_len_ as usize;
2204            while j != 0usize {
2205                {
2206                    let context: usize =
2207                        Context(prev_byte, prev_byte2, literal_context_mode) as usize;
2208                    let literal: u8 = input[(pos & mask)];
2209                    literal_enc.store_symbol_with_context(
2210                        literal as usize,
2211                        context,
2212                        mb.literal_context_map.slice(),
2213                        storage_ix,
2214                        storage,
2215                        6usize,
2216                    );
2217                    prev_byte2 = prev_byte;
2218                    prev_byte = literal;
2219                    pos = pos.wrapping_add(1);
2220                }
2221                j = j.wrapping_sub(1);
2222            }
2223        }
2224        pos = pos.wrapping_add(cmd.copy_len() as usize);
2225        if cmd.copy_len() != 0 {
2226            prev_byte2 = input[(pos.wrapping_sub(2) & mask)];
2227            prev_byte = input[(pos.wrapping_sub(1) & mask)];
2228            if cmd.cmd_prefix_ as i32 >= 128i32 {
2229                let dist_code: usize = cmd.dist_prefix_ as usize & 0x03ff;
2230                let distnumextra: u32 = u32::from(cmd.dist_prefix_) >> 10; //FIXME: from command
2231                let distextra: u64 = cmd.dist_extra_ as (u64);
2232                if mb.distance_context_map_size == 0usize {
2233                    distance_enc.store_symbol(dist_code, storage_ix, storage);
2234                } else {
2235                    distance_enc.store_symbol_with_context(
2236                        dist_code,
2237                        cmd.distance_context() as usize,
2238                        mb.distance_context_map.slice(),
2239                        storage_ix,
2240                        storage,
2241                        2usize,
2242                    );
2243                }
2244                BrotliWriteBits(distnumextra as u8, distextra, storage_ix, storage);
2245            }
2246        }
2247    }
2248    distance_enc.cleanup(alloc);
2249    command_enc.cleanup(alloc);
2250    literal_enc.cleanup(alloc);
2251    if is_last {
2252        JumpToByteBoundary(storage_ix, storage);
2253    }
2254}
2255
2256fn BuildHistograms(
2257    input: &[u8],
2258    start_pos: usize,
2259    mask: usize,
2260    commands: &[Command],
2261    n_commands: usize,
2262    lit_histo: &mut HistogramLiteral,
2263    cmd_histo: &mut HistogramCommand,
2264    dist_histo: &mut HistogramDistance,
2265) {
2266    let mut pos: usize = start_pos;
2267    for i in 0usize..n_commands {
2268        let cmd: Command = commands[i];
2269        let mut j: usize;
2270        HistogramAddItem(cmd_histo, cmd.cmd_prefix_ as usize);
2271        j = cmd.insert_len_ as usize;
2272        while j != 0usize {
2273            {
2274                HistogramAddItem(lit_histo, input[(pos & mask)] as usize);
2275                pos = pos.wrapping_add(1);
2276            }
2277            j = j.wrapping_sub(1);
2278        }
2279        pos = pos.wrapping_add(cmd.copy_len() as usize);
2280        if cmd.copy_len() != 0 && cmd.cmd_prefix_ >= 128 {
2281            HistogramAddItem(dist_histo, cmd.dist_prefix_ as usize & 0x03ff);
2282        }
2283    }
2284}
2285fn StoreDataWithHuffmanCodes(
2286    input: &[u8],
2287    start_pos: usize,
2288    mask: usize,
2289    commands: &[Command],
2290    n_commands: usize,
2291    lit_depth: &[u8],
2292    lit_bits: &[u16],
2293    cmd_depth: &[u8],
2294    cmd_bits: &[u16],
2295    dist_depth: &[u8],
2296    dist_bits: &[u16],
2297    storage_ix: &mut usize,
2298    storage: &mut [u8],
2299) {
2300    let mut pos: usize = start_pos;
2301    for i in 0usize..n_commands {
2302        let cmd: Command = commands[i];
2303        let cmd_code: usize = cmd.cmd_prefix_ as usize;
2304        let mut j: usize;
2305        BrotliWriteBits(
2306            cmd_depth[cmd_code],
2307            cmd_bits[cmd_code] as (u64),
2308            storage_ix,
2309            storage,
2310        );
2311        StoreCommandExtra(&cmd, storage_ix, storage);
2312        j = cmd.insert_len_ as usize;
2313        while j != 0usize {
2314            {
2315                let literal: u8 = input[(pos & mask)];
2316                BrotliWriteBits(
2317                    lit_depth[(literal as usize)],
2318                    lit_bits[(literal as usize)] as (u64),
2319                    storage_ix,
2320                    storage,
2321                );
2322                pos = pos.wrapping_add(1);
2323            }
2324            j = j.wrapping_sub(1);
2325        }
2326        pos = pos.wrapping_add(cmd.copy_len() as usize);
2327        if cmd.copy_len() != 0 && cmd.cmd_prefix_ >= 128 {
2328            let dist_code: usize = cmd.dist_prefix_ as usize & 0x03ff;
2329            let distnumextra: u32 = u32::from(cmd.dist_prefix_) >> 10;
2330            let distextra: u32 = cmd.dist_extra_;
2331            BrotliWriteBits(
2332                dist_depth[dist_code],
2333                dist_bits[dist_code] as (u64),
2334                storage_ix,
2335                storage,
2336            );
2337            BrotliWriteBits(distnumextra as u8, distextra as (u64), storage_ix, storage);
2338        }
2339    }
2340}
2341
2342#[cfg_attr(feature = "hotpath", hotpath::measure)]
2343pub(crate) fn store_meta_block_trivial<Alloc: BrotliAlloc, Cb>(
2344    alloc: &mut Alloc,
2345    input: &[u8],
2346    start_pos: usize,
2347    length: usize,
2348    mask: usize,
2349    is_last: bool,
2350    params: &BrotliEncoderParams,
2351    distance_cache: &[i32; kNumDistanceCacheEntries],
2352    commands: &[Command],
2353    n_commands: usize,
2354    recoder_state: &mut RecoderState,
2355    storage_ix: &mut usize,
2356    storage: &mut [u8],
2357    f: &mut Cb,
2358) where
2359    Cb: FnMut(
2360        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2361        &mut [interface::StaticCommand],
2362        InputPair,
2363        &mut Alloc,
2364    ),
2365{
2366    let (input0, input1) = InputPairFromMaskedInput(input, start_pos, length, mask);
2367    if params.log_meta_block {
2368        LogMetaBlock(
2369            alloc,
2370            commands.split_at(n_commands).0,
2371            input0,
2372            input1,
2373            distance_cache,
2374            recoder_state,
2375            block_split_nop(),
2376            params,
2377            Some(ContextType::CONTEXT_LSB6),
2378            f,
2379        );
2380    }
2381    let mut lit_histo: HistogramLiteral = HistogramLiteral::default();
2382    let mut cmd_histo: HistogramCommand = HistogramCommand::default();
2383    let mut dist_histo: HistogramDistance = HistogramDistance::default();
2384    let mut lit_depth: [u8; 256] = [0; 256];
2385    let mut lit_bits: [u16; 256] = [0; 256];
2386    let mut cmd_depth: [u8; 704] = [0; 704];
2387    let mut cmd_bits: [u16; 704] = [0; 704];
2388    let mut dist_depth: [u8; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE] =
2389        [0; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
2390    let mut dist_bits: [u16; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE] =
2391        [0; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
2392    const MAX_HUFFMAN_TREE_SIZE: usize = (2i32 * 704i32 + 1i32) as usize;
2393    let mut tree: [HuffmanTree; MAX_HUFFMAN_TREE_SIZE] = [HuffmanTree {
2394        total_count_: 0,
2395        index_left_: 0,
2396        index_right_or_value_: 0,
2397    }; MAX_HUFFMAN_TREE_SIZE];
2398    let num_distance_symbols = params.dist.alphabet_size;
2399    StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
2400    BuildHistograms(
2401        input,
2402        start_pos,
2403        mask,
2404        commands,
2405        n_commands,
2406        &mut lit_histo,
2407        &mut cmd_histo,
2408        &mut dist_histo,
2409    );
2410    BrotliWriteBits(13, 0, storage_ix, storage);
2411    BuildAndStoreHuffmanTree(
2412        lit_histo.slice_mut(),
2413        BROTLI_NUM_LITERAL_SYMBOLS,
2414        BROTLI_NUM_LITERAL_SYMBOLS,
2415        &mut tree[..],
2416        &mut lit_depth[..],
2417        &mut lit_bits[..],
2418        storage_ix,
2419        storage,
2420    );
2421    BuildAndStoreHuffmanTree(
2422        cmd_histo.slice_mut(),
2423        BROTLI_NUM_COMMAND_SYMBOLS,
2424        BROTLI_NUM_COMMAND_SYMBOLS,
2425        &mut tree[..],
2426        &mut cmd_depth[..],
2427        &mut cmd_bits[..],
2428        storage_ix,
2429        storage,
2430    );
2431    BuildAndStoreHuffmanTree(
2432        dist_histo.slice_mut(),
2433        MAX_SIMPLE_DISTANCE_ALPHABET_SIZE,
2434        num_distance_symbols as usize,
2435        &mut tree[..],
2436        &mut dist_depth[..],
2437        &mut dist_bits[..],
2438        storage_ix,
2439        storage,
2440    );
2441    StoreDataWithHuffmanCodes(
2442        input,
2443        start_pos,
2444        mask,
2445        commands,
2446        n_commands,
2447        &mut lit_depth[..],
2448        &mut lit_bits[..],
2449        &mut cmd_depth[..],
2450        &mut cmd_bits[..],
2451        &mut dist_depth[..],
2452        &mut dist_bits[..],
2453        storage_ix,
2454        storage,
2455    );
2456    if is_last {
2457        JumpToByteBoundary(storage_ix, storage);
2458    }
2459}
2460
2461fn StoreStaticCommandHuffmanTree(storage_ix: &mut usize, storage: &mut [u8]) {
2462    BrotliWriteBits(56, 0x0092_6244_1630_7003, storage_ix, storage);
2463    BrotliWriteBits(3, 0, storage_ix, storage);
2464}
2465
2466fn StoreStaticDistanceHuffmanTree(storage_ix: &mut usize, storage: &mut [u8]) {
2467    BrotliWriteBits(28, 0x0369_dc03, storage_ix, storage);
2468}
2469
2470struct BlockSplitRef<'a> {
2471    types: &'a [u8],
2472    lengths: &'a [u32],
2473    num_types: u32,
2474}
2475
2476impl<'a> Default for BlockSplitRef<'a> {
2477    fn default() -> Self {
2478        BlockSplitRef {
2479            types: &[],
2480            lengths: &[],
2481            num_types: 1,
2482        }
2483    }
2484}
2485
2486#[derive(Default)]
2487struct MetaBlockSplitRefs<'a> {
2488    btypel: BlockSplitRef<'a>,
2489    literal_context_map: &'a [u32],
2490    btypec: BlockSplitRef<'a>,
2491    btyped: BlockSplitRef<'a>,
2492    distance_context_map: &'a [u32],
2493}
2494
2495fn block_split_nop() -> MetaBlockSplitRefs<'static> {
2496    MetaBlockSplitRefs::default()
2497}
2498
2499fn block_split_reference<'a, Alloc: BrotliAlloc>(
2500    mb: &'a MetaBlockSplit<Alloc>,
2501) -> MetaBlockSplitRefs<'a> {
2502    return MetaBlockSplitRefs::<'a> {
2503        btypel: BlockSplitRef {
2504            types: mb
2505                .literal_split
2506                .types
2507                .slice()
2508                .split_at(mb.literal_split.num_blocks)
2509                .0,
2510            lengths: mb
2511                .literal_split
2512                .lengths
2513                .slice()
2514                .split_at(mb.literal_split.num_blocks)
2515                .0,
2516            num_types: mb.literal_split.num_types as u32,
2517        },
2518        literal_context_map: mb
2519            .literal_context_map
2520            .slice()
2521            .split_at(mb.literal_context_map_size)
2522            .0,
2523        btypec: BlockSplitRef {
2524            types: mb
2525                .command_split
2526                .types
2527                .slice()
2528                .split_at(mb.command_split.num_blocks)
2529                .0,
2530            lengths: mb
2531                .command_split
2532                .lengths
2533                .slice()
2534                .split_at(mb.command_split.num_blocks)
2535                .0,
2536            num_types: mb.command_split.num_types as u32,
2537        },
2538        btyped: BlockSplitRef {
2539            types: mb
2540                .distance_split
2541                .types
2542                .slice()
2543                .split_at(mb.distance_split.num_blocks)
2544                .0,
2545            lengths: mb
2546                .distance_split
2547                .lengths
2548                .slice()
2549                .split_at(mb.distance_split.num_blocks)
2550                .0,
2551            num_types: mb.distance_split.num_types as u32,
2552        },
2553        distance_context_map: mb
2554            .distance_context_map
2555            .slice()
2556            .split_at(mb.distance_context_map_size)
2557            .0,
2558    };
2559}
2560
2561#[derive(Clone, Copy, Default)]
2562pub struct RecoderState {
2563    pub num_bytes_encoded: usize,
2564}
2565
2566impl RecoderState {
2567    pub fn new() -> Self {
2568        Self::default()
2569    }
2570}
2571
2572#[cfg_attr(feature = "hotpath", hotpath::measure)]
2573pub(crate) fn store_meta_block_fast<Cb, Alloc: BrotliAlloc>(
2574    m: &mut Alloc,
2575    input: &[u8],
2576    start_pos: usize,
2577    length: usize,
2578    mask: usize,
2579    is_last: bool,
2580    params: &BrotliEncoderParams,
2581    dist_cache: &[i32; kNumDistanceCacheEntries],
2582    commands: &[Command],
2583    n_commands: usize,
2584    recoder_state: &mut RecoderState,
2585    storage_ix: &mut usize,
2586    storage: &mut [u8],
2587    cb: &mut Cb,
2588) where
2589    Cb: FnMut(
2590        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2591        &mut [StaticCommand],
2592        InputPair,
2593        &mut Alloc,
2594    ),
2595{
2596    let (input0, input1) = InputPairFromMaskedInput(input, start_pos, length, mask);
2597    if params.log_meta_block {
2598        LogMetaBlock(
2599            m,
2600            commands.split_at(n_commands).0,
2601            input0,
2602            input1,
2603            dist_cache,
2604            recoder_state,
2605            block_split_nop(),
2606            params,
2607            Some(ContextType::CONTEXT_LSB6),
2608            cb,
2609        );
2610    }
2611    let num_distance_symbols = params.dist.alphabet_size;
2612    let distance_alphabet_bits = Log2FloorNonZero(u64::from(num_distance_symbols) - 1) + 1;
2613    StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
2614    BrotliWriteBits(13, 0, storage_ix, storage);
2615    if n_commands <= 128usize {
2616        let mut histogram: [u32; 256] = [0; 256];
2617        let mut pos: usize = start_pos;
2618        let mut num_literals: usize = 0usize;
2619        let mut lit_depth: [u8; 256] = [0; 256];
2620        let mut lit_bits: [u16; 256] = [0; 256];
2621        for i in 0usize..n_commands {
2622            let cmd: Command = commands[i];
2623            let mut j: usize;
2624            j = cmd.insert_len_ as usize;
2625            while j != 0usize {
2626                {
2627                    {
2628                        let _rhs = 1;
2629                        let _lhs = &mut histogram[input[(pos & mask)] as usize];
2630                        *_lhs = (*_lhs).wrapping_add(_rhs as u32);
2631                    }
2632                    pos = pos.wrapping_add(1);
2633                }
2634                j = j.wrapping_sub(1);
2635            }
2636            num_literals = num_literals.wrapping_add(cmd.insert_len_ as usize);
2637            pos = pos.wrapping_add(cmd.copy_len() as usize);
2638        }
2639        BrotliBuildAndStoreHuffmanTreeFast(
2640            m,
2641            &mut histogram[..],
2642            num_literals,
2643            8usize,
2644            &mut lit_depth[..],
2645            &mut lit_bits[..],
2646            storage_ix,
2647            storage,
2648        );
2649        StoreStaticCommandHuffmanTree(storage_ix, storage);
2650        StoreStaticDistanceHuffmanTree(storage_ix, storage);
2651        StoreDataWithHuffmanCodes(
2652            input,
2653            start_pos,
2654            mask,
2655            commands,
2656            n_commands,
2657            &mut lit_depth[..],
2658            &mut lit_bits[..],
2659            &kStaticCommandCodeDepth[..],
2660            &kStaticCommandCodeBits[..],
2661            &kStaticDistanceCodeDepth[..],
2662            &kStaticDistanceCodeBits[..],
2663            storage_ix,
2664            storage,
2665        );
2666    } else {
2667        let mut lit_histo: HistogramLiteral = HistogramLiteral::default();
2668        let mut cmd_histo: HistogramCommand = HistogramCommand::default();
2669        let mut dist_histo: HistogramDistance = HistogramDistance::default();
2670        let mut lit_depth: [u8; 256] = [0; 256];
2671        let mut lit_bits: [u16; 256] = [0; 256];
2672        let mut cmd_depth: [u8; 704] = [0; 704];
2673        let mut cmd_bits: [u16; 704] = [0; 704];
2674        let mut dist_depth: [u8; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE] =
2675            [0; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
2676        let mut dist_bits: [u16; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE] =
2677            [0; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
2678        BuildHistograms(
2679            input,
2680            start_pos,
2681            mask,
2682            commands,
2683            n_commands,
2684            &mut lit_histo,
2685            &mut cmd_histo,
2686            &mut dist_histo,
2687        );
2688        BrotliBuildAndStoreHuffmanTreeFast(
2689            m,
2690            lit_histo.slice(),
2691            lit_histo.total_count_,
2692            8usize,
2693            &mut lit_depth[..],
2694            &mut lit_bits[..],
2695            storage_ix,
2696            storage,
2697        );
2698        BrotliBuildAndStoreHuffmanTreeFast(
2699            m,
2700            cmd_histo.slice(),
2701            cmd_histo.total_count_,
2702            10usize,
2703            &mut cmd_depth[..],
2704            &mut cmd_bits[..],
2705            storage_ix,
2706            storage,
2707        );
2708        BrotliBuildAndStoreHuffmanTreeFast(
2709            m,
2710            dist_histo.slice(),
2711            dist_histo.total_count_,
2712            distance_alphabet_bits as usize,
2713            &mut dist_depth[..],
2714            &mut dist_bits[..],
2715            storage_ix,
2716            storage,
2717        );
2718        StoreDataWithHuffmanCodes(
2719            input,
2720            start_pos,
2721            mask,
2722            commands,
2723            n_commands,
2724            &mut lit_depth[..],
2725            &mut lit_bits[..],
2726            &mut cmd_depth[..],
2727            &mut cmd_bits[..],
2728            &mut dist_depth[..],
2729            &mut dist_bits[..],
2730            storage_ix,
2731            storage,
2732        );
2733    }
2734    if is_last {
2735        JumpToByteBoundary(storage_ix, storage);
2736    }
2737}
2738fn BrotliStoreUncompressedMetaBlockHeader(
2739    length: usize,
2740    storage_ix: &mut usize,
2741    storage: &mut [u8],
2742) {
2743    let mut lenbits: u64 = 0;
2744    let mut nlenbits: u32 = 0;
2745    let mut nibblesbits: u32 = 0;
2746    BrotliWriteBits(1, 0, storage_ix, storage);
2747    BrotliEncodeMlen(length as u32, &mut lenbits, &mut nlenbits, &mut nibblesbits);
2748    BrotliWriteBits(2, nibblesbits as u64, storage_ix, storage);
2749    BrotliWriteBits(nlenbits as u8, lenbits, storage_ix, storage);
2750    BrotliWriteBits(1, 1, storage_ix, storage);
2751}
2752
2753fn InputPairFromMaskedInput(
2754    input: &[u8],
2755    position: usize,
2756    len: usize,
2757    mask: usize,
2758) -> (&[u8], &[u8]) {
2759    let masked_pos: usize = position & mask;
2760    if masked_pos.wrapping_add(len) > mask.wrapping_add(1) {
2761        let len1: usize = mask.wrapping_add(1).wrapping_sub(masked_pos);
2762        return (
2763            &input[masked_pos..(masked_pos + len1)],
2764            &input[0..len.wrapping_sub(len1)],
2765        );
2766    }
2767    (&input[masked_pos..masked_pos + len], &[])
2768}
2769
2770pub(crate) fn store_uncompressed_meta_block<Cb, Alloc: BrotliAlloc>(
2771    alloc: &mut Alloc,
2772    is_final_block: bool,
2773    input: &[u8],
2774    position: usize,
2775    mask: usize,
2776    params: &BrotliEncoderParams,
2777    len: usize,
2778    recoder_state: &mut RecoderState,
2779    storage_ix: &mut usize,
2780    storage: &mut [u8],
2781    suppress_meta_block_logging: bool,
2782    cb: &mut Cb,
2783) where
2784    Cb: FnMut(
2785        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2786        &mut [StaticCommand],
2787        InputPair,
2788        &mut Alloc,
2789    ),
2790{
2791    let (input0, input1) = InputPairFromMaskedInput(input, position, len, mask);
2792    BrotliStoreUncompressedMetaBlockHeader(len, storage_ix, storage);
2793    JumpToByteBoundary(storage_ix, storage);
2794    let dst_start0 = (*storage_ix >> 3);
2795    storage[dst_start0..(dst_start0 + input0.len())].copy_from_slice(input0);
2796    *storage_ix = storage_ix.wrapping_add(input0.len() << 3);
2797    let dst_start1 = (*storage_ix >> 3);
2798    storage[dst_start1..(dst_start1 + input1.len())].copy_from_slice(input1);
2799    *storage_ix = storage_ix.wrapping_add(input1.len() << 3);
2800    BrotliWriteBitsPrepareStorage(*storage_ix, storage);
2801    if params.log_meta_block && !suppress_meta_block_logging {
2802        let cmds = [Command {
2803            insert_len_: len as u32,
2804            copy_len_: 0,
2805            dist_extra_: 0,
2806            cmd_prefix_: 0,
2807            dist_prefix_: 0,
2808        }];
2809
2810        LogMetaBlock(
2811            alloc,
2812            &cmds,
2813            input0,
2814            input1,
2815            &[0, 0, 0, 0],
2816            recoder_state,
2817            block_split_nop(),
2818            params,
2819            None,
2820            cb,
2821        );
2822    }
2823    if is_final_block {
2824        BrotliWriteBits(1u8, 1u64, storage_ix, storage);
2825        BrotliWriteBits(1u8, 1u64, storage_ix, storage);
2826        JumpToByteBoundary(storage_ix, storage);
2827    }
2828}
2829
2830pub fn BrotliStoreSyncMetaBlock(storage_ix: &mut usize, storage: &mut [u8]) {
2831    BrotliWriteBits(6, 6, storage_ix, storage);
2832    JumpToByteBoundary(storage_ix, storage);
2833}
2834
2835pub fn BrotliWritePaddingMetaBlock(storage_ix: &mut usize, storage: &mut [u8]) {
2836    if *storage_ix & 7 != 0 {
2837        BrotliWriteBits(6, 6, storage_ix, storage);
2838        JumpToByteBoundary(storage_ix, storage);
2839    }
2840}
2841
2842pub fn BrotliWriteEmptyLastMetaBlock(storage_ix: &mut usize, storage: &mut [u8]) {
2843    BrotliWriteBits(1, 1, storage_ix, storage);
2844    BrotliWriteBits(1, 1, storage_ix, storage);
2845    JumpToByteBoundary(storage_ix, storage);
2846}
2847
2848const MAX_SIZE_ENCODING: usize = 10;
2849
2850fn encode_base_128(mut value: u64) -> (usize, [u8; MAX_SIZE_ENCODING]) {
2851    let mut ret = [0u8; MAX_SIZE_ENCODING];
2852    for index in 0..ret.len() {
2853        ret[index] = (value & 0x7f) as u8;
2854        value >>= 7;
2855        if value != 0 {
2856            ret[index] |= 0x80;
2857        } else {
2858            return (index + 1, ret);
2859        }
2860    }
2861    (ret.len(), ret)
2862}
2863
2864pub fn BrotliWriteMetadataMetaBlock(
2865    params: &BrotliEncoderParams,
2866    storage_ix: &mut usize,
2867    storage: &mut [u8],
2868) {
2869    BrotliWriteBits(1u8, 0u64, storage_ix, storage); // not last
2870    BrotliWriteBits(2u8, 3u64, storage_ix, storage); // MNIBBLES = 0 (pattern 1,1)
2871    BrotliWriteBits(1u8, 0u64, storage_ix, storage); // reserved
2872    BrotliWriteBits(2u8, 1u64, storage_ix, storage); // num bytes for length of magic number header
2873    let (size_hint_count, size_hint_b128) = encode_base_128(params.size_hint as u64);
2874
2875    BrotliWriteBits(8u8, 3 + size_hint_count as u64, storage_ix, storage); // 1 byte of data: writing 12 for the magic number header
2876    JumpToByteBoundary(storage_ix, storage);
2877    let magic_number: [u8; 3] = if params.catable && !params.use_dictionary {
2878        [0xe1, 0x97, 0x81]
2879    } else if params.appendable {
2880        [0xe1, 0x97, 0x82]
2881    } else {
2882        [0xe1, 0x97, 0x80]
2883    };
2884    for magic in magic_number.iter() {
2885        BrotliWriteBits(8u8, u64::from(*magic), storage_ix, storage);
2886    }
2887    BrotliWriteBits(8u8, u64::from(VERSION), storage_ix, storage);
2888    for sh in size_hint_b128[..size_hint_count].iter() {
2889        BrotliWriteBits(8u8, u64::from(*sh), storage_ix, storage);
2890    }
2891}
2892
2893#[cfg(test)]
2894mod test {
2895    use crate::enc::brotli_bit_stream::{MAX_SIZE_ENCODING, encode_base_128};
2896
2897    #[test]
2898    fn test_encode_base_128() {
2899        assert_eq!(encode_base_128(0), (1, [0u8; MAX_SIZE_ENCODING]));
2900        assert_eq!(encode_base_128(1), (1, [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]));
2901        assert_eq!(encode_base_128(127), (1, [0x7f, 0, 0, 0, 0, 0, 0, 0, 0, 0]));
2902        assert_eq!(
2903            encode_base_128(128),
2904            (2, [0x80, 0x1, 0, 0, 0, 0, 0, 0, 0, 0])
2905        );
2906        assert_eq!(
2907            encode_base_128(16383),
2908            (2, [0xff, 0x7f, 0, 0, 0, 0, 0, 0, 0, 0])
2909        );
2910        assert_eq!(
2911            encode_base_128(16384),
2912            (3, [0x80, 0x80, 0x1, 0, 0, 0, 0, 0, 0, 0])
2913        );
2914        assert_eq!(
2915            encode_base_128(2097151),
2916            (3, [0xff, 0xff, 0x7f, 0, 0, 0, 0, 0, 0, 0])
2917        );
2918        assert_eq!(
2919            encode_base_128(2097152),
2920            (4, [0x80, 0x80, 0x80, 0x1, 0, 0, 0, 0, 0, 0])
2921        );
2922        assert_eq!(
2923            encode_base_128(4194303),
2924            (4, [0xff, 0xff, 0xff, 0x1, 0, 0, 0, 0, 0, 0])
2925        );
2926        assert_eq!(
2927            encode_base_128(4294967295),
2928            (5, [0xff, 0xff, 0xff, 0xff, 0xf, 0, 0, 0, 0, 0])
2929        );
2930        assert_eq!(
2931            encode_base_128(4294967296),
2932            (5, [0x80, 0x80, 0x80, 0x80, 0x10, 0, 0, 0, 0, 0])
2933        );
2934        assert_eq!(
2935            encode_base_128(9223372036854775808),
2936            (
2937                10,
2938                [0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1]
2939            )
2940        );
2941        assert_eq!(
2942            encode_base_128(18446744073709551615),
2943            (
2944                10,
2945                [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1]
2946            )
2947        );
2948    }
2949}