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