1use alloc::SliceWrapperMut;
2use core::cmp::{max, min};
3
4use super::super::alloc::SliceWrapper;
5use super::histogram::CostAccessors;
6use super::util::{FastLog2, FastLog2u16};
7use super::vectorization::Mem256i;
8use crate::enc::floatX;
9
10const BROTLI_REPEAT_ZERO_CODE_LENGTH: usize = 17;
11const BROTLI_CODE_LENGTH_CODES: usize = BROTLI_REPEAT_ZERO_CODE_LENGTH + 1;
12
13pub(crate) fn shannon_entropy(mut population: &[u32], size: usize) -> (floatX, usize) {
14 let mut sum: usize = 0;
15 let mut retval: floatX = 0.0;
16
17 if (size & 1) != 0 && !population.is_empty() {
18 let p = population[0] as usize;
19 population = population.split_at(1).1;
20 sum = sum.wrapping_add(p);
21 retval -= p as floatX * FastLog2u16(p as u16);
22 }
23 for pop_iter in population.split_at((size >> 1) << 1).0 {
24 let p = *pop_iter as usize;
25 sum = sum.wrapping_add(p);
26 retval -= p as floatX * FastLog2u16(p as u16);
27 }
28 if sum != 0 {
29 retval += sum as floatX * FastLog2(sum as u64); }
31
32 (retval, sum)
33}
34
35#[inline(always)]
36pub fn BitsEntropy(population: &[u32], size: usize) -> floatX {
37 let (mut retval, sum) = shannon_entropy(population, size);
38 if retval < sum as floatX {
39 retval = sum as floatX;
40 }
41 retval
42}
43
44#[allow(clippy::excessive_precision)]
45fn CostComputation<T: SliceWrapper<Mem256i>>(
46 depth_histo: &mut [u32; BROTLI_CODE_LENGTH_CODES],
47 nnz_data: &T,
48 nnz: usize,
49 _total_count: floatX,
50 log2total: floatX,
51) -> floatX {
52 let mut bits: floatX = 0.0;
53 let mut max_depth: usize = 1;
54 for i in 0..nnz {
55 let element = nnz_data.slice()[i >> 3][i & 7];
58 let log2p = log2total - FastLog2u16(element as u16);
59 let depth = min((log2p + 0.5) as u8, 15u8);
61 bits += (element as floatX) * log2p;
62 if (depth as usize) > max_depth {
63 max_depth = depth as usize;
64 }
65 depth_histo[depth as usize] += 1;
66 }
67
68 bits += (18 + 2 * max_depth) as floatX;
70 bits += BitsEntropy(depth_histo, BROTLI_CODE_LENGTH_CODES);
72 bits
74}
75
76pub fn BrotliPopulationCost<HistogramType: SliceWrapper<u32> + CostAccessors>(
77 histogram: &HistogramType,
78 nnz_data: &mut HistogramType::i32vec,
79) -> floatX {
80 static kOneSymbolHistogramCost: floatX = 12.0;
81 static kTwoSymbolHistogramCost: floatX = 20.0;
82 static kThreeSymbolHistogramCost: floatX = 28.0;
83 static kFourSymbolHistogramCost: floatX = 37.0;
84
85 let data_size: usize = histogram.slice().len();
86 let mut count = 0;
87 let mut s: [usize; 5] = [0; 5];
88 let mut bits: floatX = 0.0;
89
90 if histogram.total_count() == 0 {
91 return kOneSymbolHistogramCost;
92 }
93 for i in 0..data_size {
94 if histogram.slice()[i] > 0 {
95 s[count] = i;
96 count += 1;
97 if count > 4 {
98 break;
99 }
100 }
101 }
102 match count {
103 1 => return kOneSymbolHistogramCost,
104 2 => return kTwoSymbolHistogramCost + histogram.total_count() as floatX,
105 3 => {
106 let histo0: u32 = histogram.slice()[s[0]];
107 let histo1: u32 = histogram.slice()[s[1]];
108 let histo2: u32 = histogram.slice()[s[2]];
109 let histomax: u32 = max(histo0, max(histo1, histo2));
110 return kThreeSymbolHistogramCost
111 + (2u32).wrapping_mul(histo0.wrapping_add(histo1).wrapping_add(histo2)) as floatX
112 - histomax as floatX;
113 }
114 4 => {
115 let mut histo: [u32; 4] = [0; 4];
116
117 for i in 0..4 {
118 histo[i] = histogram.slice()[s[i]];
119 }
120 for i in 0..4 {
121 for j in i + 1..4 {
122 if histo[j] > histo[i] {
123 histo.swap(j, i);
124 }
125 }
126 }
127 let h23: u32 = histo[2].wrapping_add(histo[3]);
128 let histomax: u32 = max(h23, histo[0]);
129 return kFourSymbolHistogramCost
130 + (3u32).wrapping_mul(h23) as floatX
131 + (2u32).wrapping_mul(histo[0].wrapping_add(histo[1])) as floatX
132 - histomax as floatX;
133 }
134 _ => {}
135 }
136
137 if cfg!(feature = "vector_scratch_space") {
138 let mut nnz: usize = 0;
140 let mut depth_histo = [0u32; 18];
141 let total_count = histogram.total_count() as floatX;
142 let log2total = FastLog2(histogram.total_count() as u64);
143 let mut i: usize = 0;
144 while i < data_size {
145 if histogram.slice()[i] > 0 {
146 let nnz_val = &mut nnz_data.slice_mut()[nnz >> 3];
147 nnz_val[nnz & 7] = histogram.slice()[i] as i32;
148 i += 1;
149 nnz += 1;
150 } else {
151 let mut reps: u32 = 1;
152 for hd in histogram.slice()[i + 1..data_size].iter() {
153 if *hd != 0 {
154 break;
155 }
156 reps += 1
157 }
158 i += reps as usize;
159 if i == data_size {
160 break;
161 }
162 if reps < 3 {
163 depth_histo[0] += reps;
164 } else {
165 reps -= 2;
166 let mut depth_histo_adds: u32 = 0;
167 while reps > 0 {
168 depth_histo_adds += 1;
169 bits += 3.0;
170 reps >>= 3;
171 }
172 depth_histo[BROTLI_REPEAT_ZERO_CODE_LENGTH] += depth_histo_adds;
173 }
174 }
175 }
176 bits += CostComputation(&mut depth_histo, nnz_data, nnz, total_count, log2total);
177 } else {
178 let mut max_depth: usize = 1;
179 let mut depth_histo = [0u32; 18];
180 let log2total: floatX = FastLog2(histogram.total_count() as u64); let mut reps: u32 = 0;
182 for histo in histogram.slice()[..data_size].iter() {
183 if *histo != 0 {
184 if reps != 0 {
185 if reps < 3 {
186 depth_histo[0] += reps;
187 } else {
188 reps -= 2;
189 while reps > 0 {
190 depth_histo[17] += 1;
191 bits += 3.0;
192 reps >>= 3;
193 }
194 }
195 reps = 0;
196 }
197 let log2p = log2total - FastLog2u16(*histo as u16);
198 let mut depth = (log2p + 0.5) as usize;
199 bits += *histo as floatX * log2p;
200 depth = min(depth, 15);
201 max_depth = max(depth, max_depth);
202 depth_histo[depth] += 1;
203 } else {
204 reps += 1;
205 }
206 }
207 bits += (18usize).wrapping_add((2usize).wrapping_mul(max_depth)) as floatX;
208 bits += BitsEntropy(&depth_histo[..], 18);
209 }
210 bits
211}