1#![allow(dead_code)]
2use super::bit_cost::BrotliPopulationCost;
3use super::histogram::{
4 CostAccessors, HistogramAddHistogram, HistogramClear, HistogramSelfAddHistogram,
5};
6use super::util::brotli_min_size_t;
7use super::util::FastLog2;
8use alloc;
9use alloc::{Allocator, SliceWrapper, SliceWrapperMut};
10use core;
11#[derive(Clone, Copy)]
12pub struct HistogramPair {
13 pub idx1: u32,
14 pub idx2: u32,
15 pub cost_combo: super::util::floatX,
16 pub cost_diff: super::util::floatX,
17}
18
19impl Default for HistogramPair {
20 #[inline(always)]
21 fn default() -> HistogramPair {
22 HistogramPair {
23 idx1: 0,
24 idx2: 0,
25 cost_combo: 0.0 as super::util::floatX,
26 cost_diff: 0.0 as super::util::floatX,
27 }
28 }
29}
30#[inline(always)]
32fn ClusterCostDiff(size_a: usize, size_b: usize) -> super::util::floatX {
33 let size_c: usize = size_a.wrapping_add(size_b);
34 size_a as (super::util::floatX) * FastLog2(size_a as u64)
35 + size_b as (super::util::floatX) * FastLog2(size_b as u64)
36 - size_c as (super::util::floatX) * FastLog2(size_c as u64)
37}
38
39#[inline(always)]
40fn brotli_max_double(a: super::util::floatX, b: super::util::floatX) -> super::util::floatX {
41 if a > b {
42 a
43 } else {
44 b
45 }
46}
47
48#[inline(always)]
49fn HistogramPairIsLess(p1: &HistogramPair, p2: &HistogramPair) -> bool {
50 if p1.cost_diff != p2.cost_diff {
51 p1.cost_diff > p2.cost_diff
52 } else {
53 p1.idx2.wrapping_sub(p1.idx1) > p2.idx2.wrapping_sub(p2.idx1)
54 }
55}
56
57fn BrotliCompareAndPushToQueue<
60 HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
61>(
62 out: &[HistogramType],
63 cluster_size: &[u32],
64 mut idx1: u32,
65 mut idx2: u32,
66 max_num_pairs: usize,
67 scratch_space: &mut HistogramType::i32vec,
68 pairs: &mut [HistogramPair],
69 num_pairs: &mut usize,
70) {
71 let mut is_good_pair: i32 = 0i32;
72 let mut p: HistogramPair = HistogramPair {
73 idx1: 0,
74 idx2: 0,
75 cost_combo: 0.0,
76 cost_diff: 0.0,
77 };
78 if idx1 == idx2 {
79 } else {
80 if idx2 < idx1 {
81 core::mem::swap(&mut idx2, &mut idx1);
82 }
83 p.idx1 = idx1;
84 p.idx2 = idx2;
85 p.cost_diff = 0.5 as super::util::floatX
86 * ClusterCostDiff(
87 cluster_size[idx1 as usize] as usize,
88 cluster_size[idx2 as usize] as usize,
89 );
90 p.cost_diff -= (out[idx1 as usize]).bit_cost();
91 p.cost_diff -= (out[idx2 as usize]).bit_cost();
92 if (out[idx1 as usize]).total_count() == 0usize {
93 p.cost_combo = (out[idx2 as usize]).bit_cost();
94 is_good_pair = 1i32;
95 } else if (out[idx2 as usize]).total_count() == 0usize {
96 p.cost_combo = (out[idx1 as usize]).bit_cost();
97 is_good_pair = 1i32;
98 } else {
99 let threshold: super::util::floatX = if *num_pairs == 0usize {
100 1e38 as super::util::floatX
101 } else {
102 brotli_max_double(0.0 as super::util::floatX, (pairs[0]).cost_diff)
103 };
104
105 let mut combo: HistogramType = out[idx1 as usize].clone();
106 HistogramAddHistogram(&mut combo, &out[idx2 as usize]);
107 let cost_combo: super::util::floatX = BrotliPopulationCost(&combo, scratch_space);
108 if cost_combo < threshold - p.cost_diff {
109 p.cost_combo = cost_combo;
110 is_good_pair = 1i32;
111 }
112 }
113 if is_good_pair != 0 {
114 p.cost_diff += p.cost_combo;
115 if *num_pairs > 0usize && HistogramPairIsLess(&pairs[0], &p) {
116 if *num_pairs < max_num_pairs {
118 pairs[*num_pairs] = pairs[0];
119 *num_pairs = num_pairs.wrapping_add(1);
120 }
121 pairs[0] = p;
122 } else if *num_pairs < max_num_pairs {
123 pairs[*num_pairs] = p;
124 *num_pairs = num_pairs.wrapping_add(1);
125 }
126 }
127 }
128}
129
130pub fn BrotliHistogramCombine<
131 HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
132>(
133 out: &mut [HistogramType],
134 cluster_size: &mut [u32],
135 symbols: &mut [u32],
136 clusters: &mut [u32],
137 pairs: &mut [HistogramPair],
138 mut num_clusters: usize,
139 symbols_size: usize,
140 max_clusters: usize,
141 max_num_pairs: usize,
142 scratch_space: &mut HistogramType::i32vec,
143) -> usize {
144 let mut cost_diff_threshold: super::util::floatX = 0.0 as super::util::floatX;
145 let mut min_cluster_size: usize = 1;
146 let mut num_pairs: usize = 0usize;
147 {
148 let mut idx1: usize;
151 idx1 = 0usize;
152 while idx1 < num_clusters {
153 {
154 let mut idx2: usize;
155 idx2 = idx1.wrapping_add(1);
156 while idx2 < num_clusters {
157 {
158 BrotliCompareAndPushToQueue(
159 out,
160 cluster_size,
161 clusters[idx1],
162 clusters[idx2],
163 max_num_pairs,
164 scratch_space,
165 pairs,
166 &mut num_pairs,
167 );
168 }
169 idx2 = idx2.wrapping_add(1);
170 }
171 }
172 idx1 = idx1.wrapping_add(1);
173 }
174 }
175 while num_clusters > min_cluster_size {
176 let mut i: usize;
177 if (pairs[0]).cost_diff >= cost_diff_threshold {
178 cost_diff_threshold = 1e38 as super::util::floatX;
179 min_cluster_size = max_clusters;
180 {
181 {
182 continue;
183 }
184 }
185 }
186 let best_idx1: u32 = (pairs[0]).idx1;
188 let best_idx2: u32 = (pairs[0]).idx2;
189 HistogramSelfAddHistogram(out, (best_idx1 as usize), (best_idx2 as usize));
190 (out[(best_idx1 as usize)]).set_bit_cost((pairs[0]).cost_combo);
191 {
192 let _rhs = cluster_size[(best_idx2 as usize)];
193 let _lhs = &mut cluster_size[(best_idx1 as usize)];
194 *_lhs = (*_lhs).wrapping_add(_rhs);
195 }
196 i = 0usize;
197 while i < symbols_size {
198 {
199 if symbols[i] == best_idx2 {
200 symbols[i] = best_idx1;
201 }
202 }
203 i = i.wrapping_add(1);
204 }
205 i = 0usize;
206 'break9: while i < num_clusters {
207 {
208 if clusters[i] == best_idx2 {
209 for offset in 0..(num_clusters - i - 1) {
210 clusters[i + offset] = clusters[i + 1 + offset];
211 }
212 break 'break9;
213 }
214 }
215 i = i.wrapping_add(1);
216 }
217 num_clusters = num_clusters.wrapping_sub(1);
218 {
219 let mut copy_to_idx: usize = 0usize;
221 i = 0usize;
222 while i < num_pairs {
223 'continue12: loop {
224 {
225 let p: HistogramPair = pairs[i];
226 if (p).idx1 == best_idx1
227 || (p).idx2 == best_idx1
228 || (p).idx1 == best_idx2
229 || (p).idx2 == best_idx2
230 {
231 {
233 break 'continue12;
234 }
235 }
236 if HistogramPairIsLess(&pairs[0], &p) {
237 let front: HistogramPair = pairs[0];
239 pairs[0] = p;
240 pairs[copy_to_idx] = front;
241 } else {
242 pairs[copy_to_idx] = p;
243 }
244 copy_to_idx = copy_to_idx.wrapping_add(1);
245 }
246 break;
247 }
248 i = i.wrapping_add(1);
249 }
250 num_pairs = copy_to_idx;
251 }
252 i = 0usize;
253 while i < num_clusters {
255 {
256 BrotliCompareAndPushToQueue(
257 out,
258 cluster_size,
259 best_idx1,
260 clusters[i],
261 max_num_pairs,
262 scratch_space,
263 pairs,
264 &mut num_pairs,
265 );
266 }
267 i = i.wrapping_add(1);
268 }
269 }
270 num_clusters
271}
272
273#[inline(always)]
275pub fn BrotliHistogramBitCostDistance<
276 HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
277>(
278 histogram: &HistogramType,
279 candidate: &HistogramType,
280 scratch_space: &mut HistogramType::i32vec,
281) -> super::util::floatX {
282 if histogram.total_count() == 0usize {
283 0.0 as super::util::floatX
284 } else {
285 let mut tmp: HistogramType = histogram.clone();
286 HistogramAddHistogram(&mut tmp, candidate);
287 BrotliPopulationCost(&tmp, scratch_space) - candidate.bit_cost()
288 }
289}
290
291pub fn BrotliHistogramRemap<
297 HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
298>(
299 inp: &[HistogramType],
300 in_size: usize,
301 clusters: &[u32],
302 num_clusters: usize,
303 scratch_space: &mut HistogramType::i32vec,
304 out: &mut [HistogramType],
305 symbols: &mut [u32],
306) {
307 let mut i: usize;
308 i = 0usize;
309 while i < in_size {
310 {
311 let mut best_out: u32 = if i == 0usize {
312 symbols[0]
313 } else {
314 symbols[i.wrapping_sub(1)]
315 };
316 let mut best_bits: super::util::floatX = BrotliHistogramBitCostDistance(
317 &inp[i],
318 &mut out[(best_out as usize)],
319 scratch_space,
320 );
321 let mut j: usize;
322 j = 0usize;
323 while j < num_clusters {
324 {
325 let cur_bits: super::util::floatX = BrotliHistogramBitCostDistance(
326 &inp[i],
327 &mut out[(clusters[j] as usize)],
328 scratch_space,
329 );
330 if cur_bits < best_bits {
331 best_bits = cur_bits;
332 best_out = clusters[j];
333 }
334 }
335 j = j.wrapping_add(1);
336 }
337 symbols[i] = best_out;
338 }
339 i = i.wrapping_add(1);
340 }
341 i = 0usize;
342 while i < num_clusters {
344 {
345 HistogramClear(&mut out[(clusters[i] as usize)]);
346 }
347 i = i.wrapping_add(1);
348 }
349 i = 0usize;
350 while i < in_size {
351 {
352 HistogramAddHistogram(&mut out[(symbols[i] as usize)], &inp[i]);
353 }
354 i = i.wrapping_add(1);
355 }
356}
357
358pub fn BrotliHistogramReindex<
369 HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
370 Alloc: alloc::Allocator<u32> + alloc::Allocator<HistogramType>,
371>(
372 alloc: &mut Alloc,
373 out: &mut [HistogramType],
374 symbols: &mut [u32],
375 length: usize,
376) -> usize {
377 static kInvalidIndex: u32 = !(0u32);
378 let mut new_index = if length != 0 {
379 <Alloc as Allocator<u32>>::alloc_cell(alloc, length)
380 } else {
381 <Alloc as Allocator<u32>>::AllocatedMemory::default()
382 };
383 let mut next_index: u32;
384 let mut tmp: <Alloc as Allocator<HistogramType>>::AllocatedMemory;
385 let mut i: usize;
386 i = 0usize;
387 while i < length {
388 {
389 new_index.slice_mut()[i] = kInvalidIndex;
390 }
391 i = i.wrapping_add(1);
392 }
393 next_index = 0u32;
394 i = 0usize;
395 while i < length {
396 {
397 if new_index.slice()[(symbols[i] as usize)] == kInvalidIndex {
398 new_index.slice_mut()[(symbols[i] as usize)] = next_index;
399 next_index = next_index.wrapping_add(1);
400 }
401 }
402 i = i.wrapping_add(1);
403 }
404 tmp = if next_index != 0 {
407 <Alloc as Allocator<HistogramType>>::alloc_cell(alloc, next_index as usize)
408 } else {
409 <Alloc as Allocator<HistogramType>>::AllocatedMemory::default()
410 };
411 next_index = 0u32;
412 i = 0usize;
413 while i < length {
414 {
415 if new_index.slice()[(symbols[i] as usize)] == next_index {
416 tmp.slice_mut()[(next_index as usize)] = out[(symbols[i] as usize)].clone();
417 next_index = next_index.wrapping_add(1);
418 }
419 symbols[i] = new_index.slice()[(symbols[i] as usize)];
420 }
421 i = i.wrapping_add(1);
422 }
423 {
424 <Alloc as Allocator<u32>>::free_cell(alloc, new_index);
425 }
426 i = 0usize;
427 while i < next_index as usize {
428 {
429 out[i] = tmp.slice()[i].clone();
430 }
431 i = i.wrapping_add(1);
432 }
433 {
434 <Alloc as Allocator<HistogramType>>::free_cell(alloc, tmp)
435 }
436 next_index as usize
437}
438
439pub fn BrotliClusterHistograms<
440 HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
441 Alloc: alloc::Allocator<u32> + alloc::Allocator<HistogramPair> + alloc::Allocator<HistogramType>,
442>(
443 alloc: &mut Alloc,
444 inp: &[HistogramType],
445 in_size: usize,
446 max_histograms: usize,
447 scratch_space: &mut HistogramType::i32vec,
448 out: &mut [HistogramType],
449 out_size: &mut usize,
450 histogram_symbols: &mut [u32],
451) {
452 let mut cluster_size = if in_size != 0 {
453 <Alloc as Allocator<u32>>::alloc_cell(alloc, in_size)
454 } else {
455 <Alloc as Allocator<u32>>::AllocatedMemory::default()
456 };
457 let mut clusters = if in_size != 0 {
458 <Alloc as Allocator<u32>>::alloc_cell(alloc, in_size)
459 } else {
460 <Alloc as Allocator<u32>>::AllocatedMemory::default()
461 };
462 let mut num_clusters: usize = 0usize;
463 let max_input_histograms: usize = 64usize;
464 let pairs_capacity: usize = max_input_histograms
465 .wrapping_mul(max_input_histograms)
466 .wrapping_div(2);
467 let mut pairs =
468 <Alloc as Allocator<HistogramPair>>::alloc_cell(alloc, pairs_capacity.wrapping_add(1));
469 let mut i: usize;
470 i = 0usize;
471 while i < in_size {
472 {
473 cluster_size.slice_mut()[i] = 1u32;
474 }
475 i = i.wrapping_add(1);
476 }
477 i = 0usize;
478 while i < in_size {
479 {
480 out[i] = inp[i].clone();
481 (out[i]).set_bit_cost(BrotliPopulationCost(&inp[i], scratch_space));
482 histogram_symbols[i] = i as u32;
483 }
484 i = i.wrapping_add(1);
485 }
486 i = 0usize;
487 while i < in_size {
488 {
489 let num_to_combine: usize =
490 brotli_min_size_t(in_size.wrapping_sub(i), max_input_histograms);
491
492 let mut j: usize;
493 j = 0usize;
494 while j < num_to_combine {
495 {
496 clusters.slice_mut()[num_clusters.wrapping_add(j)] = i.wrapping_add(j) as u32;
497 }
498 j = j.wrapping_add(1);
499 }
500 let num_new_clusters: usize = BrotliHistogramCombine(
501 out,
502 cluster_size.slice_mut(),
503 &mut histogram_symbols[i..],
504 &mut clusters.slice_mut()[num_clusters..],
505 pairs.slice_mut(),
506 num_to_combine,
507 num_to_combine,
508 max_histograms,
509 pairs_capacity,
510 scratch_space,
511 );
512 num_clusters = num_clusters.wrapping_add(num_new_clusters);
513 }
514 i = i.wrapping_add(max_input_histograms);
515 }
516 {
517 let max_num_pairs: usize = brotli_min_size_t(
518 (64usize).wrapping_mul(num_clusters),
519 num_clusters.wrapping_div(2).wrapping_mul(num_clusters),
520 );
521 {
522 if pairs_capacity < max_num_pairs.wrapping_add(1) {
523 let mut _new_size: usize = if pairs_capacity == 0usize {
524 max_num_pairs.wrapping_add(1)
525 } else {
526 pairs_capacity
527 };
528 let mut new_array: <Alloc as Allocator<HistogramPair>>::AllocatedMemory;
529 while _new_size < max_num_pairs.wrapping_add(1) {
530 _new_size = _new_size.wrapping_mul(2);
531 }
532 new_array = if _new_size != 0 {
533 <Alloc as Allocator<HistogramPair>>::alloc_cell(alloc, _new_size)
534 } else {
535 <Alloc as Allocator<HistogramPair>>::AllocatedMemory::default()
536 };
537 new_array.slice_mut()[..pairs_capacity]
538 .clone_from_slice(&pairs.slice()[..pairs_capacity]);
539 <Alloc as Allocator<HistogramPair>>::free_cell(
540 alloc,
541 core::mem::replace(&mut pairs, new_array),
542 );
543 }
544 }
545 num_clusters = BrotliHistogramCombine(
546 out,
547 cluster_size.slice_mut(),
548 histogram_symbols,
549 clusters.slice_mut(),
550 pairs.slice_mut(),
551 num_clusters,
552 in_size,
553 max_histograms,
554 max_num_pairs,
555 scratch_space,
556 );
557 }
558 <Alloc as Allocator<HistogramPair>>::free_cell(alloc, pairs);
559 <Alloc as Allocator<u32>>::free_cell(alloc, cluster_size);
560 BrotliHistogramRemap(
561 inp,
562 in_size,
563 clusters.slice(),
564 num_clusters,
565 scratch_space,
566 out,
567 histogram_symbols,
568 );
569 <Alloc as Allocator<u32>>::free_cell(alloc, clusters);
570 *out_size = BrotliHistogramReindex(alloc, out, histogram_symbols, in_size);
571}
572
573