Skip to main content

simd_brotli/enc/
metablock.rs

1use core;
2use core::cmp::{max, min};
3
4use super::super::alloc;
5use super::super::alloc::{Allocator, SliceWrapper, SliceWrapperMut};
6use super::backward_references::BrotliEncoderParams;
7use super::bit_cost::{BitsEntropy, BrotliPopulationCost};
8use super::block_split::BlockSplit;
9use super::block_splitter::BrotliSplitBlock;
10use super::brotli_bit_stream::MetaBlockSplit;
11use super::cluster::BrotliClusterHistograms;
12use super::combined_alloc::BrotliAlloc;
13use super::command::{BrotliDistanceParams, Command, PrefixEncodeCopyDistance};
14use super::constants::BROTLI_MAX_NPOSTFIX;
15use super::encode::{
16    BROTLI_DISTANCE_ALPHABET_SIZE, BROTLI_LARGE_MAX_DISTANCE_BITS, BROTLI_MAX_ALLOWED_DISTANCE,
17    BROTLI_MAX_DISTANCE_BITS,
18};
19use super::entropy_encode::BrotliOptimizeHuffmanCountsForRle;
20use super::histogram::{
21    BrotliBuildHistogramsWithContext, ClearHistograms, Context, ContextType, CostAccessors,
22    HistogramAddHistogram, HistogramAddItem, HistogramClear, HistogramCommand, HistogramDistance,
23    HistogramLiteral,
24};
25use crate::enc::combined_alloc::{alloc_default, allocate};
26use crate::enc::floatX;
27
28pub fn BrotliInitDistanceParams(params: &mut BrotliEncoderParams, npostfix: u32, ndirect: u32) {
29    let dist_params = &mut params.dist;
30    let mut alphabet_size;
31    let mut max_distance;
32
33    dist_params.distance_postfix_bits = npostfix;
34    dist_params.num_direct_distance_codes = ndirect;
35
36    alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE(npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
37    max_distance =
38        ndirect + (1u32 << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) - (1u32 << (npostfix + 2));
39
40    if (params.large_window) {
41        let bound: [u32; BROTLI_MAX_NPOSTFIX + 1] = [0, 4, 12, 28];
42        let postfix = 1u32 << npostfix;
43        alphabet_size =
44            BROTLI_DISTANCE_ALPHABET_SIZE(npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
45        /* The maximum distance is set so that no distance symbol used can encode
46        a distance larger than BROTLI_MAX_ALLOWED_DISTANCE with all
47        its extra bits set. */
48        if (ndirect < bound[npostfix as usize]) {
49            max_distance =
50                BROTLI_MAX_ALLOWED_DISTANCE as u32 - (bound[npostfix as usize] - ndirect);
51        } else if (ndirect >= bound[npostfix as usize] + postfix) {
52            max_distance = (3u32 << 29) - 4 + (ndirect - bound[npostfix as usize]);
53        } else {
54            max_distance = BROTLI_MAX_ALLOWED_DISTANCE as u32;
55        }
56    }
57
58    dist_params.alphabet_size = alphabet_size;
59    dist_params.max_distance = max_distance as usize;
60}
61
62fn RecomputeDistancePrefixes(
63    cmds: &mut [Command],
64    num_commands: usize,
65    orig_params: &BrotliDistanceParams,
66    new_params: &BrotliDistanceParams,
67) {
68    if orig_params.distance_postfix_bits == new_params.distance_postfix_bits
69        && orig_params.num_direct_distance_codes == new_params.num_direct_distance_codes
70    {
71        return;
72    }
73
74    for cmd in cmds.split_at_mut(num_commands).0.iter_mut() {
75        if (cmd.copy_len() != 0 && cmd.cmd_prefix_ >= 128) {
76            let ret = cmd.restore_distance_code(orig_params);
77            PrefixEncodeCopyDistance(
78                ret as usize,
79                new_params.num_direct_distance_codes as usize,
80                new_params.distance_postfix_bits as u64,
81                &mut cmd.dist_prefix_,
82                &mut cmd.dist_extra_,
83            );
84        }
85    }
86}
87
88fn ComputeDistanceCost(
89    cmds: &[Command],
90    num_commands: usize,
91    orig_params: &BrotliDistanceParams,
92    new_params: &BrotliDistanceParams,
93    scratch: &mut <HistogramDistance as CostAccessors>::i32vec,
94    cost: &mut f64,
95) -> bool {
96    let mut equal_params = false;
97    let mut dist_prefix: u16 = 0;
98    let mut dist_extra: u32 = 0;
99    let mut extra_bits: f64 = 0.0;
100    let mut histo = HistogramDistance::default();
101
102    if (orig_params.distance_postfix_bits == new_params.distance_postfix_bits
103        && orig_params.num_direct_distance_codes == new_params.num_direct_distance_codes)
104    {
105        equal_params = true;
106    }
107    for cmd in cmds.split_at(num_commands).0 {
108        if cmd.copy_len() != 0 && cmd.cmd_prefix_ >= 128 {
109            if equal_params {
110                dist_prefix = cmd.dist_prefix_;
111            } else {
112                let distance = cmd.restore_distance_code(orig_params);
113                if distance > new_params.max_distance as u32 {
114                    return false;
115                }
116                PrefixEncodeCopyDistance(
117                    distance as usize,
118                    new_params.num_direct_distance_codes as usize,
119                    new_params.distance_postfix_bits as u64,
120                    &mut dist_prefix,
121                    &mut dist_extra,
122                );
123            }
124            HistogramAddItem(&mut histo, (dist_prefix & 0x03ff) as usize);
125            extra_bits += (dist_prefix >> 10) as f64;
126        }
127    }
128
129    *cost = BrotliPopulationCost(&histo, scratch) as f64 + extra_bits;
130    true
131}
132
133#[cfg_attr(feature = "hotpath", hotpath::measure)]
134pub fn BrotliBuildMetaBlock<Alloc: BrotliAlloc>(
135    alloc: &mut Alloc,
136    ringbuffer: &[u8],
137    pos: usize,
138    mask: usize,
139    params: &mut BrotliEncoderParams,
140    prev_byte: u8,
141    prev_byte2: u8,
142    cmds: &mut [Command],
143    num_commands: usize,
144    literal_context_mode: ContextType,
145    lit_scratch_space: &mut <HistogramLiteral as CostAccessors>::i32vec,
146    cmd_scratch_space: &mut <HistogramCommand as CostAccessors>::i32vec,
147    dst_scratch_space: &mut <HistogramDistance as CostAccessors>::i32vec,
148    mb: &mut MetaBlockSplit<Alloc>,
149) {
150    static kMaxNumberOfHistograms: usize = 256usize;
151    let mut distance_histograms: <Alloc as Allocator<HistogramDistance>>::AllocatedMemory;
152    let mut literal_histograms: <Alloc as Allocator<HistogramLiteral>>::AllocatedMemory;
153    let mut literal_context_modes = alloc_default::<ContextType, Alloc>();
154
155    let mut i: usize;
156    let mut literal_context_multiplier: usize = 1;
157    let mut ndirect_msb: u32 = 0;
158    let mut check_orig = true;
159    if !params.avoid_distance_prefix_search {
160        let mut best_dist_cost: f64 = 1e99;
161        let orig_params = params.clone();
162        let mut new_params = params.clone();
163
164        for npostfix in 0..(BROTLI_MAX_NPOSTFIX + 1) {
165            while ndirect_msb < 16 {
166                let ndirect = ndirect_msb << npostfix;
167
168                let mut dist_cost: f64 = 0.0;
169                BrotliInitDistanceParams(&mut new_params, npostfix as u32, ndirect);
170                if npostfix as u32 == orig_params.dist.distance_postfix_bits
171                    && ndirect == orig_params.dist.num_direct_distance_codes
172                {
173                    check_orig = false;
174                }
175                let skip: bool = !ComputeDistanceCost(
176                    cmds,
177                    num_commands,
178                    &orig_params.dist,
179                    &new_params.dist,
180                    dst_scratch_space,
181                    &mut dist_cost,
182                );
183                if skip || (dist_cost > best_dist_cost) {
184                    break;
185                }
186                best_dist_cost = dist_cost;
187                params.dist = new_params.dist;
188                ndirect_msb += 1;
189            }
190            ndirect_msb = ndirect_msb.saturating_sub(1);
191            ndirect_msb /= 2;
192        }
193        if check_orig {
194            let mut dist_cost: f64 = 0.0;
195            ComputeDistanceCost(
196                cmds,
197                num_commands,
198                &orig_params.dist,
199                &orig_params.dist,
200                dst_scratch_space,
201                &mut dist_cost,
202            );
203            if dist_cost < best_dist_cost {
204                // best_dist_cost = dist_cost; unused
205                params.dist = orig_params.dist;
206            }
207        }
208        RecomputeDistancePrefixes(cmds, num_commands, &orig_params.dist, &params.dist);
209    }
210    BrotliSplitBlock(
211        alloc,
212        cmds,
213        num_commands,
214        ringbuffer,
215        pos,
216        mask,
217        params,
218        lit_scratch_space,
219        cmd_scratch_space,
220        dst_scratch_space,
221        &mut mb.literal_split,
222        &mut mb.command_split,
223        &mut mb.distance_split,
224    );
225    if params.disable_literal_context_modeling == 0 {
226        literal_context_multiplier = (1i32 << 6) as usize;
227        literal_context_modes = allocate::<ContextType, _>(alloc, mb.literal_split.num_types);
228        for item in literal_context_modes.slice_mut().iter_mut() {
229            *item = literal_context_mode;
230        }
231    }
232    let literal_histograms_size: usize = mb
233        .literal_split
234        .num_types
235        .wrapping_mul(literal_context_multiplier);
236    literal_histograms = allocate::<HistogramLiteral, _>(alloc, literal_histograms_size);
237    let distance_histograms_size: usize = mb.distance_split.num_types << 2;
238    distance_histograms = allocate::<HistogramDistance, _>(alloc, distance_histograms_size);
239    mb.command_histograms_size = mb.command_split.num_types;
240    mb.command_histograms = allocate::<HistogramCommand, _>(alloc, mb.command_histograms_size);
241    BrotliBuildHistogramsWithContext(
242        cmds,
243        num_commands,
244        &mut mb.literal_split,
245        &mut mb.command_split,
246        &mut mb.distance_split,
247        ringbuffer,
248        pos,
249        mask,
250        prev_byte,
251        prev_byte2,
252        literal_context_modes.slice(),
253        literal_histograms.slice_mut(),
254        mb.command_histograms.slice_mut(),
255        distance_histograms.slice_mut(),
256    );
257    <Alloc as Allocator<ContextType>>::free_cell(alloc, literal_context_modes);
258    mb.literal_context_map_size = mb.literal_split.num_types << 6;
259    mb.literal_context_map = allocate::<u32, _>(alloc, mb.literal_context_map_size);
260    mb.literal_histograms_size = mb.literal_context_map_size;
261    mb.literal_histograms = allocate::<HistogramLiteral, _>(alloc, mb.literal_histograms_size);
262    BrotliClusterHistograms(
263        alloc,
264        literal_histograms.slice(),
265        literal_histograms_size,
266        kMaxNumberOfHistograms,
267        lit_scratch_space,
268        mb.literal_histograms.slice_mut(),
269        &mut mb.literal_histograms_size,
270        mb.literal_context_map.slice_mut(),
271    );
272    <Alloc as Allocator<HistogramLiteral>>::free_cell(alloc, literal_histograms);
273    if params.disable_literal_context_modeling != 0 {
274        i = mb.literal_split.num_types;
275        while i != 0usize {
276            let mut j: usize = 0usize;
277            i = i.wrapping_sub(1);
278            while j < (1i32 << 6) as usize {
279                {
280                    let val = mb.literal_context_map.slice()[i];
281                    mb.literal_context_map.slice_mut()[(i << 6).wrapping_add(j)] = val;
282                }
283                j = j.wrapping_add(1);
284            }
285        }
286    }
287    mb.distance_context_map_size = mb.distance_split.num_types << 2;
288    mb.distance_context_map = allocate::<u32, _>(alloc, mb.distance_context_map_size);
289    mb.distance_histograms_size = mb.distance_context_map_size;
290    mb.distance_histograms = allocate::<HistogramDistance, _>(alloc, mb.distance_histograms_size);
291    BrotliClusterHistograms(
292        alloc,
293        distance_histograms.slice(),
294        mb.distance_context_map_size,
295        kMaxNumberOfHistograms,
296        dst_scratch_space,
297        mb.distance_histograms.slice_mut(),
298        &mut mb.distance_histograms_size,
299        mb.distance_context_map.slice_mut(),
300    );
301    <Alloc as Allocator<HistogramDistance>>::free_cell(alloc, distance_histograms);
302}
303
304/*
305pub struct BlockSplitter<'a, HistogramType:SliceWrapper<u32>+SliceWrapperMut<u32> +CostAccessors,
306                         AllocU8:alloc::Allocator<u8>+'a,
307                         AllocU32:alloc::Allocator<u32>+'a,
308                         AllocHT:alloc::Allocator<HistogramType>+'a > {
309                         */
310pub struct BlockSplitter {
311    pub alphabet_size_: usize,
312    pub min_block_size_: usize,
313    pub split_threshold_: floatX,
314    pub num_blocks_: usize,
315    //  pub split_: &'a mut BlockSplit<AllocU8, AllocU32>,
316    //  pub histograms_: AllocHT::AllocatedMemory, // FIXME: pull this one out at the end
317    //  pub histograms_size_: &'a mut usize, // FIXME: pull this one out at the end
318    pub target_block_size_: usize,
319    pub block_size_: usize,
320    pub curr_histogram_ix_: usize,
321    pub last_histogram_ix_: [usize; 2],
322    pub last_entropy_: [floatX; 2],
323    pub merge_last_count_: usize,
324}
325
326pub struct ContextBlockSplitter {
327    pub alphabet_size_: usize,
328    pub num_contexts_: usize,
329    pub max_block_types_: usize,
330    pub min_block_size_: usize,
331    pub split_threshold_: floatX,
332    pub num_blocks_: usize,
333    //  pub split_: &'a mut BlockSplit<AllocU8, AllocU32>,
334    //  pub histograms_: AllocHL::AllocatedMemory,
335    //  pub histograms_size_: &'a mut usize, // FIXME: pull this one out at the end
336    pub target_block_size_: usize,
337    pub block_size_: usize,
338    pub curr_histogram_ix_: usize,
339    pub last_histogram_ix_: [usize; 2],
340    pub last_entropy_: [floatX; 2 * BROTLI_MAX_STATIC_CONTEXTS],
341    pub merge_last_count_: usize,
342}
343
344enum LitBlocks {
345    plain(BlockSplitter),      //<'a, HistogramLiteral, AllocU8, AllocU32, AllocHL>,
346    ctx(ContextBlockSplitter), //<'a, AllocU8, AllocU32, AllocHL>,
347}
348
349/*
350
351pub struct BlockSplitterCommand {
352  pub alphabet_size_: usize,
353  pub min_block_size_: usize,
354  pub split_threshold_: floatX,
355  pub num_blocks_: usize,
356  pub split_: *mut BlockSplit,
357  pub histograms_: *mut HistogramCommand,
358  pub histograms_size_: *mut usize,
359  pub target_block_size_: usize,
360  pub block_size_: usize,
361  pub curr_histogram_ix_: usize,
362  pub last_histogram_ix_: [usize; 2],
363  pub last_entropy_: [floatX; 2],
364  pub merge_last_count_: usize,
365}
366
367
368
369pub struct BlockSplitterDistance {
370  pub alphabet_size_: usize,
371  pub min_block_size_: usize,
372  pub split_threshold_: floatX,
373  pub num_blocks_: usize,
374  pub split_: *mut BlockSplit,
375  pub histograms_: *mut HistogramDistance,
376  pub histograms_size_: *mut usize,
377  pub target_block_size_: usize,
378  pub block_size_: usize,
379  pub curr_histogram_ix_: usize,
380  pub last_histogram_ix_: [usize; 2],
381  pub last_entropy_: [floatX; 2],
382  pub merge_last_count_: usize,
383}
384*/
385
386fn InitBlockSplitter<
387    HistogramType: SliceWrapper<u32> + SliceWrapperMut<u32> + CostAccessors,
388    Alloc: alloc::Allocator<u8> + alloc::Allocator<u32> + alloc::Allocator<HistogramType>,
389>(
390    alloc: &mut Alloc,
391    alphabet_size: usize,
392    min_block_size: usize,
393    split_threshold: floatX,
394    num_symbols: usize,
395    split: &mut BlockSplit<Alloc>,
396    histograms: &mut <Alloc as Allocator<HistogramType>>::AllocatedMemory,
397    histograms_size: &mut usize,
398) -> BlockSplitter {
399    let max_num_blocks: usize = num_symbols.wrapping_div(min_block_size).wrapping_add(1);
400    let max_num_types: usize = min(max_num_blocks, (256i32 + 1i32) as usize);
401    let mut xself = BlockSplitter {
402        last_entropy_: [0.0; 2],
403        alphabet_size_: alphabet_size,
404        min_block_size_: min_block_size,
405        split_threshold_: split_threshold,
406        num_blocks_: 0usize,
407        //xself.split_ : split,
408        //xself.histograms_size_ : histograms_size,
409        target_block_size_: min_block_size,
410        block_size_: 0usize,
411        curr_histogram_ix_: 0usize,
412        merge_last_count_: 0usize,
413        last_histogram_ix_: [0; 2],
414    };
415    {
416        if split.types.slice().len() < max_num_blocks {
417            let mut _new_size: usize = if split.types.slice().is_empty() {
418                max_num_blocks
419            } else {
420                split.types.slice().len()
421            };
422            let mut new_array: <Alloc as Allocator<u8>>::AllocatedMemory;
423            while _new_size < max_num_blocks {
424                _new_size = _new_size.wrapping_mul(2);
425            }
426            new_array = allocate::<u8, _>(alloc, _new_size);
427            if (!split.types.slice().is_empty()) {
428                new_array.slice_mut()[..split.types.slice().len()]
429                    .copy_from_slice(split.types.slice());
430            }
431            <Alloc as Allocator<u8>>::free_cell(
432                alloc,
433                core::mem::replace(&mut split.types, new_array),
434            );
435        }
436    }
437    {
438        if split.lengths.slice().len() < max_num_blocks {
439            let mut _new_size: usize = if split.lengths.slice().is_empty() {
440                max_num_blocks
441            } else {
442                split.lengths.slice().len()
443            };
444            while _new_size < max_num_blocks {
445                _new_size = _new_size.wrapping_mul(2);
446            }
447            let mut new_array = allocate::<u32, _>(alloc, _new_size);
448            new_array.slice_mut()[..split.lengths.slice().len()]
449                .copy_from_slice(split.lengths.slice());
450            <Alloc as Allocator<u32>>::free_cell(
451                alloc,
452                core::mem::replace(&mut split.lengths, new_array),
453            );
454        }
455    }
456    split.num_blocks = max_num_blocks;
457    *histograms_size = max_num_types;
458    let hlocal = allocate::<HistogramType, _>(alloc, *histograms_size);
459    <Alloc as Allocator<HistogramType>>::free_cell(
460        alloc,
461        core::mem::replace(&mut *histograms, hlocal),
462    );
463    HistogramClear(&mut histograms.slice_mut()[0]);
464    xself.last_histogram_ix_[0] = 0;
465    xself.last_histogram_ix_[1] = 0;
466    xself
467}
468fn InitContextBlockSplitter<
469    Alloc: alloc::Allocator<u8> + alloc::Allocator<u32> + alloc::Allocator<HistogramLiteral>,
470>(
471    alloc: &mut Alloc,
472    alphabet_size: usize,
473    num_contexts: usize,
474    min_block_size: usize,
475    split_threshold: floatX,
476    num_symbols: usize,
477    split: &mut BlockSplit<Alloc>,
478    histograms: &mut <Alloc as Allocator<HistogramLiteral>>::AllocatedMemory,
479    histograms_size: &mut usize,
480) -> ContextBlockSplitter {
481    let max_num_blocks: usize = num_symbols.wrapping_div(min_block_size).wrapping_add(1);
482
483    assert!(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
484    let mut xself = ContextBlockSplitter {
485        alphabet_size_: alphabet_size,
486        num_contexts_: num_contexts,
487        max_block_types_: (256usize).wrapping_div(num_contexts),
488        min_block_size_: min_block_size,
489        split_threshold_: split_threshold,
490        num_blocks_: 0usize,
491        //        histograms_size_: histograms_size,
492        target_block_size_: min_block_size,
493        block_size_: 0usize,
494        curr_histogram_ix_: 0usize,
495        merge_last_count_: 0usize,
496        last_histogram_ix_: [0; 2],
497        last_entropy_: [0.0; 2 * BROTLI_MAX_STATIC_CONTEXTS],
498    };
499    let max_num_types: usize = min(max_num_blocks, xself.max_block_types_.wrapping_add(1));
500    {
501        if split.types.slice().len() < max_num_blocks {
502            let mut _new_size: usize = if split.types.slice().is_empty() {
503                max_num_blocks
504            } else {
505                split.types.slice().len()
506            };
507            while _new_size < max_num_blocks {
508                _new_size = _new_size.wrapping_mul(2);
509            }
510            let mut new_array = allocate::<u8, _>(alloc, _new_size);
511            if (!split.types.slice().is_empty()) {
512                new_array.slice_mut()[..split.types.slice().len()]
513                    .copy_from_slice(split.types.slice());
514            }
515            <Alloc as Allocator<u8>>::free_cell(
516                alloc,
517                core::mem::replace(&mut split.types, new_array),
518            );
519        }
520    }
521    {
522        if split.lengths.slice().len() < max_num_blocks {
523            let mut _new_size: usize = if split.lengths.slice().is_empty() {
524                max_num_blocks
525            } else {
526                split.lengths.slice().len()
527            };
528            while _new_size < max_num_blocks {
529                _new_size = _new_size.wrapping_mul(2);
530            }
531            let mut new_array = allocate::<u32, _>(alloc, _new_size);
532            if (!split.lengths.slice().is_empty()) {
533                new_array.slice_mut()[..split.lengths.slice().len()]
534                    .copy_from_slice(split.lengths.slice());
535            }
536            <Alloc as Allocator<u32>>::free_cell(
537                alloc,
538                core::mem::replace(&mut split.lengths, new_array),
539            );
540        }
541    }
542    split.num_blocks = max_num_blocks;
543    *histograms_size = max_num_types.wrapping_mul(num_contexts);
544    *histograms = allocate::<HistogramLiteral, _>(alloc, *histograms_size);
545    //xself.histograms_ = *histograms;
546    ClearHistograms(&mut histograms.slice_mut()[0..], num_contexts);
547    xself.last_histogram_ix_[0] = 0;
548    xself.last_histogram_ix_[1] = 0;
549    xself
550}
551
552fn BlockSplitterFinishBlock<
553    HistogramType: SliceWrapper<u32> + SliceWrapperMut<u32> + CostAccessors + Clone,
554    Alloc: alloc::Allocator<u8> + alloc::Allocator<u32>,
555>(
556    xself: &mut BlockSplitter,
557    split: &mut BlockSplit<Alloc>,
558    histograms: &mut [HistogramType],
559    histograms_size: &mut usize,
560    is_final: bool,
561) {
562    xself.block_size_ = max(xself.block_size_, xself.min_block_size_);
563    if xself.num_blocks_ == 0usize {
564        split.lengths.slice_mut()[0] = xself.block_size_ as u32;
565        split.types.slice_mut()[0] = 0u8;
566        xself.last_entropy_[0] = BitsEntropy((histograms[0]).slice(), xself.alphabet_size_);
567        xself.last_entropy_[1] = xself.last_entropy_[0];
568        xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
569        split.num_types = split.num_types.wrapping_add(1);
570        xself.curr_histogram_ix_ = xself.curr_histogram_ix_.wrapping_add(1);
571        if xself.curr_histogram_ix_ < *histograms_size {
572            HistogramClear(&mut histograms[xself.curr_histogram_ix_]);
573        }
574        xself.block_size_ = 0usize;
575    } else if xself.block_size_ > 0usize {
576        let entropy = BitsEntropy(
577            (histograms[xself.curr_histogram_ix_]).slice(),
578            xself.alphabet_size_,
579        );
580        let mut combined_histo: [HistogramType; 2] = [
581            histograms[xself.curr_histogram_ix_].clone(),
582            histograms[xself.curr_histogram_ix_].clone(),
583        ];
584
585        let mut combined_entropy: [floatX; 2] = [0.0, 0.0];
586        let mut diff: [floatX; 2] = [0.0, 0.0];
587        for j in 0..2 {
588            let last_histogram_ix: usize = xself.last_histogram_ix_[j];
589            HistogramAddHistogram(&mut combined_histo[j], &histograms[last_histogram_ix]);
590            combined_entropy[j] = BitsEntropy(
591                &mut combined_histo[j].slice_mut()[0..],
592                xself.alphabet_size_,
593            );
594            diff[j] = combined_entropy[j] - entropy - xself.last_entropy_[j];
595        }
596        if split.num_types < 256usize
597            && (diff[0] > xself.split_threshold_)
598            && (diff[1] > xself.split_threshold_)
599        {
600            split.lengths.slice_mut()[xself.num_blocks_] = xself.block_size_ as u32;
601            split.types.slice_mut()[xself.num_blocks_] = split.num_types as u8;
602            xself.last_histogram_ix_[1] = xself.last_histogram_ix_[0];
603            xself.last_histogram_ix_[0] = split.num_types as u8 as usize;
604            xself.last_entropy_[1] = xself.last_entropy_[0];
605            xself.last_entropy_[0] = entropy;
606            xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
607            split.num_types = split.num_types.wrapping_add(1);
608            xself.curr_histogram_ix_ = xself.curr_histogram_ix_.wrapping_add(1);
609            if xself.curr_histogram_ix_ < *histograms_size {
610                HistogramClear(&mut histograms[xself.curr_histogram_ix_]);
611            }
612            xself.block_size_ = 0usize;
613            xself.merge_last_count_ = 0usize;
614            xself.target_block_size_ = xself.min_block_size_;
615        } else if diff[1] < diff[0] - 20.0 {
616            split.lengths.slice_mut()[xself.num_blocks_] = xself.block_size_ as u32;
617            split.types.slice_mut()[xself.num_blocks_] =
618                split.types.slice()[xself.num_blocks_.wrapping_sub(2)]; //FIXME: investigate copy?
619            {
620                xself.last_histogram_ix_.swap(0, 1);
621            }
622            histograms[xself.last_histogram_ix_[0]] = combined_histo[1].clone();
623            xself.last_entropy_[1] = xself.last_entropy_[0];
624            xself.last_entropy_[0] = combined_entropy[1];
625            xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
626            xself.block_size_ = 0usize;
627            HistogramClear(&mut histograms[xself.curr_histogram_ix_]);
628            xself.merge_last_count_ = 0usize;
629            xself.target_block_size_ = xself.min_block_size_;
630        } else {
631            {
632                let _rhs = xself.block_size_ as u32;
633                let _lhs = &mut split.lengths.slice_mut()[xself.num_blocks_.wrapping_sub(1)];
634                *_lhs = (*_lhs).wrapping_add(_rhs);
635            }
636            histograms[xself.last_histogram_ix_[0]] = combined_histo[0].clone();
637            xself.last_entropy_[0] = combined_entropy[0];
638            if split.num_types == 1 {
639                xself.last_entropy_[1] = xself.last_entropy_[0];
640            }
641            xself.block_size_ = 0usize;
642            HistogramClear(&mut histograms[xself.curr_histogram_ix_]);
643            if {
644                xself.merge_last_count_ = xself.merge_last_count_.wrapping_add(1);
645                xself.merge_last_count_
646            } > 1
647            {
648                xself.target_block_size_ =
649                    xself.target_block_size_.wrapping_add(xself.min_block_size_);
650            }
651        }
652    }
653    if is_final {
654        *histograms_size = split.num_types;
655        split.num_blocks = xself.num_blocks_;
656    }
657}
658const BROTLI_MAX_STATIC_CONTEXTS: usize = 13;
659
660fn ContextBlockSplitterFinishBlock<
661    Alloc: alloc::Allocator<u8> + alloc::Allocator<u32> + alloc::Allocator<HistogramLiteral>,
662    AllocHL: alloc::Allocator<HistogramLiteral>,
663>(
664    xself: &mut ContextBlockSplitter,
665    m: &mut AllocHL,
666    split: &mut BlockSplit<Alloc>,
667    histograms: &mut [HistogramLiteral],
668    histograms_size: &mut usize,
669    is_final: bool,
670) {
671    let num_contexts: usize = xself.num_contexts_;
672    if xself.block_size_ < xself.min_block_size_ {
673        xself.block_size_ = xself.min_block_size_;
674    }
675    if xself.num_blocks_ == 0usize {
676        split.lengths.slice_mut()[0] = xself.block_size_ as u32;
677        split.types.slice_mut()[0] = 0u8;
678        for i in 0usize..num_contexts {
679            xself.last_entropy_[i] = BitsEntropy((histograms[i]).slice(), xself.alphabet_size_);
680            xself.last_entropy_[num_contexts.wrapping_add(i)] = xself.last_entropy_[i];
681        }
682        xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
683        split.num_types = split.num_types.wrapping_add(1);
684        xself.curr_histogram_ix_ = xself.curr_histogram_ix_.wrapping_add(num_contexts);
685        if xself.curr_histogram_ix_ < *histograms_size {
686            ClearHistograms(
687                &mut histograms[xself.curr_histogram_ix_..],
688                xself.num_contexts_,
689            );
690        }
691        xself.block_size_ = 0usize;
692    } else if xself.block_size_ > 0usize {
693        let mut entropy = [0.0; BROTLI_MAX_STATIC_CONTEXTS];
694        let mut combined_histo = m.alloc_cell(2 * num_contexts);
695        let mut combined_entropy = [0.0; 2 * BROTLI_MAX_STATIC_CONTEXTS];
696        let mut diff = [0.0; 2];
697        for i in 0usize..num_contexts {
698            let curr_histo_ix: usize = xself.curr_histogram_ix_.wrapping_add(i);
699            let mut j: usize;
700            entropy[i] = BitsEntropy((histograms[curr_histo_ix]).slice(), xself.alphabet_size_);
701            j = 0usize;
702            while j < 2usize {
703                {
704                    let jx: usize = j.wrapping_mul(num_contexts).wrapping_add(i);
705                    let last_histogram_ix: usize = xself.last_histogram_ix_[j].wrapping_add(i);
706                    combined_histo.slice_mut()[jx] = histograms[curr_histo_ix].clone();
707                    HistogramAddHistogram(
708                        &mut combined_histo.slice_mut()[jx],
709                        &mut histograms[last_histogram_ix],
710                    );
711                    combined_entropy[jx] =
712                        BitsEntropy(combined_histo.slice()[jx].slice(), xself.alphabet_size_);
713                    diff[j] += combined_entropy[jx] - entropy[i] - xself.last_entropy_[jx];
714                }
715                j = j.wrapping_add(1);
716            }
717        }
718        if split.num_types < xself.max_block_types_
719            && (diff[0] > xself.split_threshold_)
720            && (diff[1] > xself.split_threshold_)
721        {
722            split.lengths.slice_mut()[xself.num_blocks_] = xself.block_size_ as u32;
723            split.types.slice_mut()[xself.num_blocks_] = split.num_types as u8;
724            xself.last_histogram_ix_[1] = xself.last_histogram_ix_[0];
725            xself.last_histogram_ix_[0] = split.num_types.wrapping_mul(num_contexts);
726            for i in 0usize..num_contexts {
727                xself.last_entropy_[num_contexts.wrapping_add(i)] = xself.last_entropy_[i];
728                xself.last_entropy_[i] = entropy[i];
729            }
730            xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
731            split.num_types = split.num_types.wrapping_add(1);
732            xself.curr_histogram_ix_ = xself.curr_histogram_ix_.wrapping_add(num_contexts);
733            if xself.curr_histogram_ix_ < *histograms_size {
734                ClearHistograms(
735                    &mut histograms[xself.curr_histogram_ix_..],
736                    xself.num_contexts_,
737                );
738            }
739            xself.block_size_ = 0usize;
740            xself.merge_last_count_ = 0usize;
741            xself.target_block_size_ = xself.min_block_size_;
742        } else if diff[1] < diff[0] - 20.0 {
743            split.lengths.slice_mut()[xself.num_blocks_] = xself.block_size_ as u32;
744            let nbm2 = split.types.slice()[xself.num_blocks_.wrapping_sub(2)];
745            split.types.slice_mut()[xself.num_blocks_] = nbm2;
746
747            {
748                xself.last_histogram_ix_.swap(0, 1);
749            }
750            for i in 0usize..num_contexts {
751                histograms[xself.last_histogram_ix_[0].wrapping_add(i)] =
752                    combined_histo.slice()[num_contexts.wrapping_add(i)].clone();
753                xself.last_entropy_[num_contexts.wrapping_add(i)] = xself.last_entropy_[i];
754                xself.last_entropy_[i] = combined_entropy[num_contexts.wrapping_add(i)];
755                HistogramClear(&mut histograms[xself.curr_histogram_ix_.wrapping_add(i)]);
756            }
757            xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
758            xself.block_size_ = 0usize;
759            xself.merge_last_count_ = 0usize;
760            xself.target_block_size_ = xself.min_block_size_;
761        } else {
762            {
763                let _rhs = xself.block_size_ as u32;
764                let _lhs = &mut split.lengths.slice_mut()[xself.num_blocks_.wrapping_sub(1)];
765                let old_split_length = *_lhs;
766                *_lhs = old_split_length.wrapping_add(_rhs);
767            }
768            for i in 0usize..num_contexts {
769                histograms[xself.last_histogram_ix_[0].wrapping_add(i)] =
770                    combined_histo.slice()[i].clone();
771                xself.last_entropy_[i] = combined_entropy[i];
772                if split.num_types == 1 {
773                    xself.last_entropy_[num_contexts.wrapping_add(i)] = xself.last_entropy_[i];
774                }
775                HistogramClear(&mut histograms[xself.curr_histogram_ix_.wrapping_add(i)]);
776            }
777            xself.block_size_ = 0usize;
778            if {
779                xself.merge_last_count_ = xself.merge_last_count_.wrapping_add(1);
780                xself.merge_last_count_
781            } > 1
782            {
783                xself.target_block_size_ =
784                    xself.target_block_size_.wrapping_add(xself.min_block_size_);
785            }
786        }
787        m.free_cell(combined_histo);
788    }
789    if is_final {
790        *histograms_size = split.num_types.wrapping_mul(num_contexts);
791        split.num_blocks = xself.num_blocks_;
792    }
793}
794
795fn BlockSplitterAddSymbol<
796    HistogramType: SliceWrapper<u32> + SliceWrapperMut<u32> + CostAccessors + Clone,
797    Alloc: alloc::Allocator<u8> + alloc::Allocator<u32>,
798>(
799    xself: &mut BlockSplitter,
800    split: &mut BlockSplit<Alloc>,
801    histograms: &mut [HistogramType],
802    histograms_size: &mut usize,
803    symbol: usize,
804) {
805    HistogramAddItem(&mut histograms[xself.curr_histogram_ix_], symbol);
806    xself.block_size_ = xself.block_size_.wrapping_add(1);
807    if xself.block_size_ == xself.target_block_size_ {
808        BlockSplitterFinishBlock(xself, split, histograms, histograms_size, false);
809    }
810}
811
812fn ContextBlockSplitterAddSymbol<
813    Alloc: alloc::Allocator<u8> + alloc::Allocator<u32> + alloc::Allocator<HistogramLiteral>,
814>(
815    xself: &mut ContextBlockSplitter,
816    m: &mut Alloc,
817    split: &mut BlockSplit<Alloc>,
818    histograms: &mut [HistogramLiteral],
819    histograms_size: &mut usize,
820    symbol: usize,
821    context: usize,
822) {
823    HistogramAddItem(
824        &mut histograms[xself.curr_histogram_ix_.wrapping_add(context)],
825        symbol,
826    );
827    xself.block_size_ = xself.block_size_.wrapping_add(1);
828    if xself.block_size_ == xself.target_block_size_ {
829        ContextBlockSplitterFinishBlock(xself, m, split, histograms, histograms_size, false);
830    }
831}
832
833fn MapStaticContexts<
834    Alloc: alloc::Allocator<u8>
835        + alloc::Allocator<u32>
836        + alloc::Allocator<HistogramLiteral>
837        + alloc::Allocator<HistogramCommand>
838        + alloc::Allocator<HistogramDistance>,
839>(
840    m32: &mut Alloc,
841    num_contexts: usize,
842    static_context_map: &[u32],
843    mb: &mut MetaBlockSplit<Alloc>,
844) {
845    mb.literal_context_map_size = mb.literal_split.num_types << 6;
846    let new_literal_context_map = allocate::<u32, _>(m32, mb.literal_context_map_size);
847    <Alloc as Allocator<u32>>::free_cell(
848        m32,
849        core::mem::replace(&mut mb.literal_context_map, new_literal_context_map),
850    );
851    for i in 0usize..mb.literal_split.num_types {
852        let offset: u32 = i.wrapping_mul(num_contexts) as u32;
853        for j in 0usize..(1u32 << 6) as usize {
854            mb.literal_context_map.slice_mut()[(i << 6).wrapping_add(j)] =
855                offset.wrapping_add(static_context_map[j]);
856        }
857    }
858}
859pub fn BrotliBuildMetaBlockGreedyInternal<
860    Alloc: alloc::Allocator<u8>
861        + alloc::Allocator<u32>
862        + alloc::Allocator<HistogramLiteral>
863        + alloc::Allocator<HistogramCommand>
864        + alloc::Allocator<HistogramDistance>,
865>(
866    alloc: &mut Alloc,
867    ringbuffer: &[u8],
868    mut pos: usize,
869    mask: usize,
870    mut prev_byte: u8,
871    mut prev_byte2: u8,
872    literal_context_mode: ContextType,
873    num_contexts: usize,
874    static_context_map: &[u32],
875    commands: &[Command],
876    n_commands: usize,
877    mb: &mut MetaBlockSplit<Alloc>,
878) {
879    let mut lit_blocks: LitBlocks;
880    let mut cmd_blocks: BlockSplitter;
881    let mut dist_blocks: BlockSplitter;
882    let mut num_literals: usize = 0usize;
883    for i in 0usize..n_commands {
884        num_literals = num_literals.wrapping_add((commands[i]).insert_len_ as usize);
885    }
886    lit_blocks = if num_contexts == 1 {
887        LitBlocks::plain(InitBlockSplitter::<HistogramLiteral, Alloc>(
888            alloc,
889            256usize,
890            512usize,
891            400.0,
892            num_literals,
893            &mut mb.literal_split,
894            &mut mb.literal_histograms,
895            &mut mb.literal_histograms_size,
896        ))
897    } else {
898        LitBlocks::ctx(InitContextBlockSplitter::<Alloc>(
899            alloc,
900            256usize,
901            num_contexts,
902            512usize,
903            400.0,
904            num_literals,
905            &mut mb.literal_split,
906            &mut mb.literal_histograms,
907            &mut mb.literal_histograms_size,
908        ))
909    };
910    cmd_blocks = InitBlockSplitter::<HistogramCommand, Alloc>(
911        alloc,
912        704usize,
913        1024usize,
914        500.0,
915        n_commands,
916        &mut mb.command_split,
917        &mut mb.command_histograms,
918        &mut mb.command_histograms_size,
919    );
920    dist_blocks = InitBlockSplitter::<HistogramDistance, Alloc>(
921        alloc,
922        64usize,
923        512usize,
924        100.0,
925        n_commands,
926        &mut mb.distance_split,
927        &mut mb.distance_histograms,
928        &mut mb.distance_histograms_size,
929    );
930
931    for i in 0usize..n_commands {
932        let cmd: Command = commands[i];
933        let mut j: usize;
934        BlockSplitterAddSymbol(
935            &mut cmd_blocks,
936            &mut mb.command_split,
937            mb.command_histograms.slice_mut(),
938            &mut mb.command_histograms_size,
939            cmd.cmd_prefix_ as usize,
940        );
941        j = cmd.insert_len_ as usize;
942        while j != 0usize {
943            {
944                let literal: u8 = ringbuffer[(pos & mask)];
945                match (&mut lit_blocks) {
946                    &mut LitBlocks::plain(ref mut lit_blocks_plain) => BlockSplitterAddSymbol(
947                        lit_blocks_plain,
948                        &mut mb.literal_split,
949                        mb.literal_histograms.slice_mut(),
950                        &mut mb.literal_histograms_size,
951                        literal as usize,
952                    ),
953                    &mut LitBlocks::ctx(ref mut lit_blocks_ctx) => {
954                        let context: usize =
955                            Context(prev_byte, prev_byte2, literal_context_mode) as usize;
956                        ContextBlockSplitterAddSymbol(
957                            lit_blocks_ctx,
958                            alloc,
959                            &mut mb.literal_split,
960                            mb.literal_histograms.slice_mut(),
961                            &mut mb.literal_histograms_size,
962                            literal as usize,
963                            static_context_map[(context as usize)] as usize,
964                        );
965                    }
966                }
967                prev_byte2 = prev_byte;
968                prev_byte = literal;
969                pos = pos.wrapping_add(1);
970            }
971            j = j.wrapping_sub(1);
972        }
973        pos = pos.wrapping_add(cmd.copy_len() as usize);
974        if cmd.copy_len() != 0 {
975            prev_byte2 = ringbuffer[(pos.wrapping_sub(2) & mask)];
976            prev_byte = ringbuffer[(pos.wrapping_sub(1) & mask)];
977            if cmd.cmd_prefix_ as i32 >= 128i32 {
978                BlockSplitterAddSymbol(
979                    &mut dist_blocks,
980                    &mut mb.distance_split,
981                    mb.distance_histograms.slice_mut(),
982                    &mut mb.distance_histograms_size,
983                    cmd.dist_prefix_ as usize & 0x3ff,
984                );
985            }
986        }
987    }
988    match (&mut lit_blocks) {
989        &mut LitBlocks::plain(ref mut lit_blocks_plain) => BlockSplitterFinishBlock(
990            lit_blocks_plain,
991            &mut mb.literal_split,
992            mb.literal_histograms.slice_mut(),
993            &mut mb.literal_histograms_size,
994            true,
995        ),
996        &mut LitBlocks::ctx(ref mut lit_blocks_ctx) => ContextBlockSplitterFinishBlock(
997            lit_blocks_ctx,
998            alloc,
999            &mut mb.literal_split,
1000            mb.literal_histograms.slice_mut(),
1001            &mut mb.literal_histograms_size,
1002            true,
1003        ),
1004    }
1005    BlockSplitterFinishBlock(
1006        &mut cmd_blocks,
1007        &mut mb.command_split,
1008        mb.command_histograms.slice_mut(),
1009        &mut mb.command_histograms_size,
1010        true,
1011    );
1012    BlockSplitterFinishBlock(
1013        &mut dist_blocks,
1014        &mut mb.distance_split,
1015        mb.distance_histograms.slice_mut(),
1016        &mut mb.distance_histograms_size,
1017        true,
1018    );
1019    if num_contexts > 1 {
1020        MapStaticContexts(alloc, num_contexts, static_context_map, mb);
1021    }
1022}
1023#[cfg_attr(feature = "hotpath", hotpath::measure)]
1024pub fn BrotliBuildMetaBlockGreedy<
1025    Alloc: alloc::Allocator<u8>
1026        + alloc::Allocator<u32>
1027        + alloc::Allocator<HistogramLiteral>
1028        + alloc::Allocator<HistogramCommand>
1029        + alloc::Allocator<HistogramDistance>,
1030>(
1031    alloc: &mut Alloc,
1032    ringbuffer: &[u8],
1033    pos: usize,
1034    mask: usize,
1035    prev_byte: u8,
1036    prev_byte2: u8,
1037    literal_context_mode: ContextType,
1038    _literal_context_lut: &[u8],
1039    num_contexts: usize,
1040    static_context_map: &[u32],
1041    commands: &[Command],
1042    n_commands: usize,
1043    mb: &mut MetaBlockSplit<Alloc>,
1044) {
1045    if num_contexts == 1 {
1046        BrotliBuildMetaBlockGreedyInternal(
1047            alloc,
1048            ringbuffer,
1049            pos,
1050            mask,
1051            prev_byte,
1052            prev_byte2,
1053            literal_context_mode,
1054            1,
1055            &[],
1056            commands,
1057            n_commands,
1058            mb,
1059        );
1060    } else {
1061        BrotliBuildMetaBlockGreedyInternal(
1062            alloc,
1063            ringbuffer,
1064            pos,
1065            mask,
1066            prev_byte,
1067            prev_byte2,
1068            literal_context_mode,
1069            num_contexts,
1070            static_context_map,
1071            commands,
1072            n_commands,
1073            mb,
1074        );
1075    }
1076}
1077
1078#[cfg_attr(feature = "hotpath", hotpath::measure)]
1079pub fn BrotliOptimizeHistograms<
1080    Alloc: alloc::Allocator<u8>
1081        + alloc::Allocator<u32>
1082        + alloc::Allocator<HistogramLiteral>
1083        + alloc::Allocator<HistogramCommand>
1084        + alloc::Allocator<HistogramDistance>,
1085>(
1086    num_distance_codes: usize,
1087    mb: &mut MetaBlockSplit<Alloc>,
1088) {
1089    let mut good_for_rle: [u8; 704] = [0; 704];
1090    for i in 0usize..mb.literal_histograms_size {
1091        BrotliOptimizeHuffmanCountsForRle(
1092            256usize,
1093            mb.literal_histograms.slice_mut()[i].slice_mut(),
1094            &mut good_for_rle[..],
1095        );
1096    }
1097    for i in 0usize..mb.command_histograms_size {
1098        BrotliOptimizeHuffmanCountsForRle(
1099            704usize,
1100            mb.command_histograms.slice_mut()[i].slice_mut(),
1101            &mut good_for_rle[..],
1102        );
1103    }
1104    for i in 0usize..mb.distance_histograms_size {
1105        BrotliOptimizeHuffmanCountsForRle(
1106            num_distance_codes,
1107            mb.distance_histograms.slice_mut()[i].slice_mut(),
1108            &mut good_for_rle[..],
1109        );
1110    }
1111}