File: | out/../deps/brotli/c/enc/./histogram_inc.h |
Warning: | line 19, column 3 Null pointer passed to 1st parameter expecting 'nonnull' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Copyright 2015 Google Inc. All Rights Reserved. | ||||||
2 | |||||||
3 | Distributed under MIT license. | ||||||
4 | See file LICENSE for detail or copy at https://opensource.org/licenses/MIT | ||||||
5 | */ | ||||||
6 | |||||||
7 | /* Algorithms for distributing the literals and commands of a metablock between | ||||||
8 | block types and contexts. */ | ||||||
9 | |||||||
10 | #include "./metablock.h" | ||||||
11 | |||||||
12 | #include "../common/constants.h" | ||||||
13 | #include "../common/context.h" | ||||||
14 | #include "../common/platform.h" | ||||||
15 | #include <brotli/types.h> | ||||||
16 | #include "./bit_cost.h" | ||||||
17 | #include "./block_splitter.h" | ||||||
18 | #include "./cluster.h" | ||||||
19 | #include "./entropy_encode.h" | ||||||
20 | #include "./histogram.h" | ||||||
21 | #include "./memory.h" | ||||||
22 | #include "./quality.h" | ||||||
23 | |||||||
24 | #if defined(__cplusplus) || defined(c_plusplus) | ||||||
25 | extern "C" { | ||||||
26 | #endif | ||||||
27 | |||||||
28 | void BrotliInitDistanceParams(BrotliEncoderParams* params, | ||||||
29 | uint32_t npostfix, uint32_t ndirect) { | ||||||
30 | BrotliDistanceParams* dist_params = ¶ms->dist; | ||||||
31 | uint32_t alphabet_size_max; | ||||||
32 | uint32_t alphabet_size_limit; | ||||||
33 | uint32_t max_distance; | ||||||
34 | |||||||
35 | dist_params->distance_postfix_bits = npostfix; | ||||||
36 | dist_params->num_direct_distance_codes = ndirect; | ||||||
37 | |||||||
38 | alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(( 16 + (ndirect) + ((24U) << ((npostfix) + 1))) | ||||||
39 | npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS)( 16 + (ndirect) + ((24U) << ((npostfix) + 1))); | ||||||
40 | alphabet_size_limit = alphabet_size_max; | ||||||
41 | max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS24U + npostfix + 2)) - | ||||||
42 | (1U << (npostfix + 2)); | ||||||
43 | |||||||
44 | if (params->large_window) { | ||||||
45 | BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit( | ||||||
46 | BROTLI_MAX_ALLOWED_DISTANCE0x7FFFFFFC, npostfix, ndirect); | ||||||
47 | alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(( 16 + (ndirect) + ((62U) << ((npostfix) + 1))) | ||||||
48 | npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS)( 16 + (ndirect) + ((62U) << ((npostfix) + 1))); | ||||||
49 | alphabet_size_limit = limit.max_alphabet_size; | ||||||
50 | max_distance = limit.max_distance; | ||||||
51 | } | ||||||
52 | |||||||
53 | dist_params->alphabet_size_max = alphabet_size_max; | ||||||
54 | dist_params->alphabet_size_limit = alphabet_size_limit; | ||||||
55 | dist_params->max_distance = max_distance; | ||||||
56 | } | ||||||
57 | |||||||
58 | static void RecomputeDistancePrefixes(Command* cmds, | ||||||
59 | size_t num_commands, | ||||||
60 | const BrotliDistanceParams* orig_params, | ||||||
61 | const BrotliDistanceParams* new_params) { | ||||||
62 | size_t i; | ||||||
63 | |||||||
64 | if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits && | ||||||
65 | orig_params->num_direct_distance_codes == | ||||||
66 | new_params->num_direct_distance_codes) { | ||||||
67 | return; | ||||||
68 | } | ||||||
69 | |||||||
70 | for (i = 0; i < num_commands; ++i) { | ||||||
71 | Command* cmd = &cmds[i]; | ||||||
72 | if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) { | ||||||
73 | PrefixEncodeCopyDistance(CommandRestoreDistanceCode(cmd, orig_params), | ||||||
74 | new_params->num_direct_distance_codes, | ||||||
75 | new_params->distance_postfix_bits, | ||||||
76 | &cmd->dist_prefix_, | ||||||
77 | &cmd->dist_extra_); | ||||||
78 | } | ||||||
79 | } | ||||||
80 | } | ||||||
81 | |||||||
82 | static BROTLI_BOOLint ComputeDistanceCost(const Command* cmds, | ||||||
83 | size_t num_commands, | ||||||
84 | const BrotliDistanceParams* orig_params, | ||||||
85 | const BrotliDistanceParams* new_params, | ||||||
86 | double* cost) { | ||||||
87 | size_t i; | ||||||
88 | BROTLI_BOOLint equal_params = BROTLI_FALSE0; | ||||||
89 | uint16_t dist_prefix; | ||||||
90 | uint32_t dist_extra; | ||||||
91 | double extra_bits = 0.0; | ||||||
92 | HistogramDistance histo; | ||||||
93 | HistogramClearDistance(&histo); | ||||||
94 | |||||||
95 | if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits && | ||||||
96 | orig_params->num_direct_distance_codes == | ||||||
97 | new_params->num_direct_distance_codes) { | ||||||
98 | equal_params = BROTLI_TRUE1; | ||||||
99 | } | ||||||
100 | |||||||
101 | for (i = 0; i < num_commands; i++) { | ||||||
102 | const Command* cmd = &cmds[i]; | ||||||
103 | if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) { | ||||||
104 | if (equal_params) { | ||||||
105 | dist_prefix = cmd->dist_prefix_; | ||||||
106 | } else { | ||||||
107 | uint32_t distance = CommandRestoreDistanceCode(cmd, orig_params); | ||||||
108 | if (distance > new_params->max_distance) { | ||||||
109 | return BROTLI_FALSE0; | ||||||
110 | } | ||||||
111 | PrefixEncodeCopyDistance(distance, | ||||||
112 | new_params->num_direct_distance_codes, | ||||||
113 | new_params->distance_postfix_bits, | ||||||
114 | &dist_prefix, | ||||||
115 | &dist_extra); | ||||||
116 | } | ||||||
117 | HistogramAddDistance(&histo, dist_prefix & 0x3FF); | ||||||
118 | extra_bits += dist_prefix >> 10; | ||||||
119 | } | ||||||
120 | } | ||||||
121 | |||||||
122 | *cost = BrotliPopulationCostDistance(&histo) + extra_bits; | ||||||
123 | return BROTLI_TRUE1; | ||||||
124 | } | ||||||
125 | |||||||
126 | void BrotliBuildMetaBlock(MemoryManager* m, | ||||||
127 | const uint8_t* ringbuffer, | ||||||
128 | const size_t pos, | ||||||
129 | const size_t mask, | ||||||
130 | BrotliEncoderParams* params, | ||||||
131 | uint8_t prev_byte, | ||||||
132 | uint8_t prev_byte2, | ||||||
133 | Command* cmds, | ||||||
134 | size_t num_commands, | ||||||
135 | ContextType literal_context_mode, | ||||||
136 | MetaBlockSplit* mb) { | ||||||
137 | /* Histogram ids need to fit in one byte. */ | ||||||
138 | static const size_t kMaxNumberOfHistograms = 256; | ||||||
139 | HistogramDistance* distance_histograms; | ||||||
140 | HistogramLiteral* literal_histograms; | ||||||
141 | ContextType* literal_context_modes = NULL((void*)0); | ||||||
142 | size_t literal_histograms_size; | ||||||
143 | size_t distance_histograms_size; | ||||||
144 | size_t i; | ||||||
145 | size_t literal_context_multiplier = 1; | ||||||
146 | uint32_t npostfix; | ||||||
147 | uint32_t ndirect_msb = 0; | ||||||
148 | BROTLI_BOOLint check_orig = BROTLI_TRUE1; | ||||||
149 | double best_dist_cost = 1e99; | ||||||
150 | BrotliEncoderParams orig_params = *params; | ||||||
151 | BrotliEncoderParams new_params = *params; | ||||||
152 | |||||||
153 | for (npostfix = 0; npostfix <= BROTLI_MAX_NPOSTFIX3; npostfix++) { | ||||||
154 | for (; ndirect_msb < 16; ndirect_msb++) { | ||||||
155 | uint32_t ndirect = ndirect_msb << npostfix; | ||||||
156 | BROTLI_BOOLint skip; | ||||||
157 | double dist_cost; | ||||||
158 | BrotliInitDistanceParams(&new_params, npostfix, ndirect); | ||||||
159 | if (npostfix == orig_params.dist.distance_postfix_bits && | ||||||
160 | ndirect == orig_params.dist.num_direct_distance_codes) { | ||||||
161 | check_orig = BROTLI_FALSE0; | ||||||
162 | } | ||||||
163 | skip = !ComputeDistanceCost( | ||||||
164 | cmds, num_commands, | ||||||
165 | &orig_params.dist, &new_params.dist, &dist_cost); | ||||||
166 | if (skip || (dist_cost > best_dist_cost)) { | ||||||
167 | break; | ||||||
168 | } | ||||||
169 | best_dist_cost = dist_cost; | ||||||
170 | params->dist = new_params.dist; | ||||||
171 | } | ||||||
172 | if (ndirect_msb > 0) ndirect_msb--; | ||||||
173 | ndirect_msb /= 2; | ||||||
174 | } | ||||||
175 | if (check_orig) { | ||||||
176 | double dist_cost; | ||||||
177 | ComputeDistanceCost(cmds, num_commands, | ||||||
178 | &orig_params.dist, &orig_params.dist, &dist_cost); | ||||||
179 | if (dist_cost < best_dist_cost) { | ||||||
180 | /* NB: currently unused; uncomment when more param tuning is added. */ | ||||||
181 | /* best_dist_cost = dist_cost; */ | ||||||
182 | params->dist = orig_params.dist; | ||||||
183 | } | ||||||
184 | } | ||||||
185 | RecomputeDistancePrefixes(cmds, num_commands, | ||||||
186 | &orig_params.dist, ¶ms->dist); | ||||||
187 | |||||||
188 | BrotliSplitBlock(m, cmds, num_commands, | ||||||
189 | ringbuffer, pos, mask, params, | ||||||
190 | &mb->literal_split, | ||||||
191 | &mb->command_split, | ||||||
192 | &mb->distance_split); | ||||||
193 | if (BROTLI_IS_OOM(m)(!!0)) return; | ||||||
194 | |||||||
195 | if (!params->disable_literal_context_modeling) { | ||||||
196 | literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS6; | ||||||
197 | literal_context_modes = | ||||||
198 | BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types)((mb->literal_split.num_types) > 0 ? ((ContextType*)BrotliAllocate ((m), (mb->literal_split.num_types) * sizeof(ContextType)) ) : ((void*)0)); | ||||||
199 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(literal_context_modes)(!!0)) return; | ||||||
200 | for (i = 0; i < mb->literal_split.num_types; ++i) { | ||||||
201 | literal_context_modes[i] = literal_context_mode; | ||||||
202 | } | ||||||
203 | } | ||||||
204 | |||||||
205 | literal_histograms_size = | ||||||
206 | mb->literal_split.num_types * literal_context_multiplier; | ||||||
207 | literal_histograms = | ||||||
208 | BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size)((literal_histograms_size) > 0 ? ((HistogramLiteral*)BrotliAllocate ((m), (literal_histograms_size) * sizeof(HistogramLiteral))) : ((void*)0)); | ||||||
209 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(literal_histograms)(!!0)) return; | ||||||
210 | ClearHistogramsLiteral(literal_histograms, literal_histograms_size); | ||||||
211 | |||||||
212 | distance_histograms_size = | ||||||
213 | mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS2; | ||||||
214 | distance_histograms = | ||||||
215 | BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size)((distance_histograms_size) > 0 ? ((HistogramDistance*)BrotliAllocate ((m), (distance_histograms_size) * sizeof(HistogramDistance)) ) : ((void*)0)); | ||||||
216 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(distance_histograms)(!!0)) return; | ||||||
217 | ClearHistogramsDistance(distance_histograms, distance_histograms_size); | ||||||
218 | |||||||
219 | BROTLI_DCHECK(mb->command_histograms == 0); | ||||||
220 | mb->command_histograms_size = mb->command_split.num_types; | ||||||
221 | mb->command_histograms = | ||||||
222 | BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size)((mb->command_histograms_size) > 0 ? ((HistogramCommand *)BrotliAllocate((m), (mb->command_histograms_size) * sizeof (HistogramCommand))) : ((void*)0)); | ||||||
223 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(mb->command_histograms)(!!0)) return; | ||||||
224 | ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size); | ||||||
225 | |||||||
226 | BrotliBuildHistogramsWithContext(cmds, num_commands, | ||||||
227 | &mb->literal_split, &mb->command_split, &mb->distance_split, | ||||||
228 | ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes, | ||||||
229 | literal_histograms, mb->command_histograms, distance_histograms); | ||||||
230 | BROTLI_FREE(m, literal_context_modes){ BrotliFree((m), (literal_context_modes)); literal_context_modes = ((void*)0); }; | ||||||
231 | |||||||
232 | BROTLI_DCHECK(mb->literal_context_map == 0); | ||||||
233 | mb->literal_context_map_size = | ||||||
234 | mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS6; | ||||||
235 | mb->literal_context_map = | ||||||
236 | BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size)((mb->literal_context_map_size) > 0 ? ((uint32_t*)BrotliAllocate ((m), (mb->literal_context_map_size) * sizeof(uint32_t))) : ((void*)0)); | ||||||
237 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(mb->literal_context_map)(!!0)) return; | ||||||
238 | |||||||
239 | BROTLI_DCHECK(mb->literal_histograms == 0); | ||||||
240 | mb->literal_histograms_size = mb->literal_context_map_size; | ||||||
241 | mb->literal_histograms = | ||||||
242 | BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size)((mb->literal_histograms_size) > 0 ? ((HistogramLiteral *)BrotliAllocate((m), (mb->literal_histograms_size) * sizeof (HistogramLiteral))) : ((void*)0)); | ||||||
243 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(mb->literal_histograms)(!!0)) return; | ||||||
244 | |||||||
245 | BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size, | ||||||
246 | kMaxNumberOfHistograms, mb->literal_histograms, | ||||||
247 | &mb->literal_histograms_size, mb->literal_context_map); | ||||||
248 | if (BROTLI_IS_OOM(m)(!!0)) return; | ||||||
249 | BROTLI_FREE(m, literal_histograms){ BrotliFree((m), (literal_histograms)); literal_histograms = ((void*)0); }; | ||||||
250 | |||||||
251 | if (params->disable_literal_context_modeling) { | ||||||
252 | /* Distribute assignment to all contexts. */ | ||||||
253 | for (i = mb->literal_split.num_types; i != 0;) { | ||||||
254 | size_t j = 0; | ||||||
255 | i--; | ||||||
256 | for (; j < (1 << BROTLI_LITERAL_CONTEXT_BITS6); j++) { | ||||||
257 | mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS6) + j] = | ||||||
258 | mb->literal_context_map[i]; | ||||||
259 | } | ||||||
260 | } | ||||||
261 | } | ||||||
262 | |||||||
263 | BROTLI_DCHECK(mb->distance_context_map == 0); | ||||||
264 | mb->distance_context_map_size = | ||||||
265 | mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS2; | ||||||
266 | mb->distance_context_map = | ||||||
267 | BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size)((mb->distance_context_map_size) > 0 ? ((uint32_t*)BrotliAllocate ((m), (mb->distance_context_map_size) * sizeof(uint32_t))) : ((void*)0)); | ||||||
268 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(mb->distance_context_map)(!!0)) return; | ||||||
269 | |||||||
270 | BROTLI_DCHECK(mb->distance_histograms == 0); | ||||||
271 | mb->distance_histograms_size = mb->distance_context_map_size; | ||||||
272 | mb->distance_histograms = | ||||||
273 | BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size)((mb->distance_histograms_size) > 0 ? ((HistogramDistance *)BrotliAllocate((m), (mb->distance_histograms_size) * sizeof (HistogramDistance))) : ((void*)0)); | ||||||
274 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(mb->distance_histograms)(!!0)) return; | ||||||
275 | |||||||
276 | BrotliClusterHistogramsDistance(m, distance_histograms, | ||||||
277 | mb->distance_context_map_size, | ||||||
278 | kMaxNumberOfHistograms, | ||||||
279 | mb->distance_histograms, | ||||||
280 | &mb->distance_histograms_size, | ||||||
281 | mb->distance_context_map); | ||||||
282 | if (BROTLI_IS_OOM(m)(!!0)) return; | ||||||
283 | BROTLI_FREE(m, distance_histograms){ BrotliFree((m), (distance_histograms)); distance_histograms = ((void*)0); }; | ||||||
284 | } | ||||||
285 | |||||||
286 | #define FN(X) X ## Literal | ||||||
287 | #include "./metablock_inc.h" /* NOLINT(build/include) */ | ||||||
288 | #undef FN | ||||||
289 | |||||||
290 | #define FN(X) X ## Command | ||||||
291 | #include "./metablock_inc.h" /* NOLINT(build/include) */ | ||||||
292 | #undef FN | ||||||
293 | |||||||
294 | #define FN(X) X ## Distance | ||||||
295 | #include "./metablock_inc.h" /* NOLINT(build/include) */ | ||||||
296 | #undef FN | ||||||
297 | |||||||
298 | #define BROTLI_MAX_STATIC_CONTEXTS13 13 | ||||||
299 | |||||||
300 | /* Greedy block splitter for one block category (literal, command or distance). | ||||||
301 | Gathers histograms for all context buckets. */ | ||||||
302 | typedef struct ContextBlockSplitter { | ||||||
303 | /* Alphabet size of particular block category. */ | ||||||
304 | size_t alphabet_size_; | ||||||
305 | size_t num_contexts_; | ||||||
306 | size_t max_block_types_; | ||||||
307 | /* We collect at least this many symbols for each block. */ | ||||||
308 | size_t min_block_size_; | ||||||
309 | /* We merge histograms A and B if | ||||||
310 | entropy(A+B) < entropy(A) + entropy(B) + split_threshold_, | ||||||
311 | where A is the current histogram and B is the histogram of the last or the | ||||||
312 | second last block type. */ | ||||||
313 | double split_threshold_; | ||||||
314 | |||||||
315 | size_t num_blocks_; | ||||||
316 | BlockSplit* split_; /* not owned */ | ||||||
317 | HistogramLiteral* histograms_; /* not owned */ | ||||||
318 | size_t* histograms_size_; /* not owned */ | ||||||
319 | |||||||
320 | /* The number of symbols that we want to collect before deciding on whether | ||||||
321 | or not to merge the block with a previous one or emit a new block. */ | ||||||
322 | size_t target_block_size_; | ||||||
323 | /* The number of symbols in the current histogram. */ | ||||||
324 | size_t block_size_; | ||||||
325 | /* Offset of the current histogram. */ | ||||||
326 | size_t curr_histogram_ix_; | ||||||
327 | /* Offset of the histograms of the previous two block types. */ | ||||||
328 | size_t last_histogram_ix_[2]; | ||||||
329 | /* Entropy of the previous two block types. */ | ||||||
330 | double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS13]; | ||||||
331 | /* The number of times we merged the current block with the last one. */ | ||||||
332 | size_t merge_last_count_; | ||||||
333 | } ContextBlockSplitter; | ||||||
334 | |||||||
335 | static void InitContextBlockSplitter( | ||||||
336 | MemoryManager* m, ContextBlockSplitter* self, size_t alphabet_size, | ||||||
337 | size_t num_contexts, size_t min_block_size, double split_threshold, | ||||||
338 | size_t num_symbols, BlockSplit* split, HistogramLiteral** histograms, | ||||||
339 | size_t* histograms_size) { | ||||||
340 | size_t max_num_blocks = num_symbols / min_block_size + 1; | ||||||
341 | size_t max_num_types; | ||||||
342 | BROTLI_DCHECK(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS); | ||||||
343 | |||||||
344 | self->alphabet_size_ = alphabet_size; | ||||||
345 | self->num_contexts_ = num_contexts; | ||||||
346 | self->max_block_types_ = BROTLI_MAX_NUMBER_OF_BLOCK_TYPES256 / num_contexts; | ||||||
347 | self->min_block_size_ = min_block_size; | ||||||
348 | self->split_threshold_ = split_threshold; | ||||||
349 | self->num_blocks_ = 0; | ||||||
350 | self->split_ = split; | ||||||
351 | self->histograms_size_ = histograms_size; | ||||||
352 | self->target_block_size_ = min_block_size; | ||||||
353 | self->block_size_ = 0; | ||||||
354 | self->curr_histogram_ix_ = 0; | ||||||
355 | self->merge_last_count_ = 0; | ||||||
356 | |||||||
357 | /* We have to allocate one more histogram than the maximum number of block | ||||||
358 | types for the current histogram when the meta-block is too big. */ | ||||||
359 | max_num_types = | ||||||
360 | BROTLI_MIN(size_t, max_num_blocks, self->max_block_types_ + 1)(brotli_min_size_t((max_num_blocks), (self->max_block_types_ + 1))); | ||||||
361 | BROTLI_ENSURE_CAPACITY(m, uint8_t,{ if (split->types_alloc_size < (max_num_blocks)) { size_t _new_size = (split->types_alloc_size == 0) ? (max_num_blocks ) : split->types_alloc_size; uint8_t* new_array; while (_new_size < (max_num_blocks)) _new_size *= 2; new_array = ((_new_size ) > 0 ? ((uint8_t*)BrotliAllocate(((m)), (_new_size) * sizeof (uint8_t))) : ((void*)0)); if (!(!!0) && !(!!0) && split->types_alloc_size != 0) memcpy(new_array, split-> types, split->types_alloc_size * sizeof(uint8_t)); { BrotliFree (((m)), (split->types)); split->types = ((void*)0); }; split ->types = new_array; split->types_alloc_size = _new_size ; } } | ||||||
362 | split->types, split->types_alloc_size, max_num_blocks){ if (split->types_alloc_size < (max_num_blocks)) { size_t _new_size = (split->types_alloc_size == 0) ? (max_num_blocks ) : split->types_alloc_size; uint8_t* new_array; while (_new_size < (max_num_blocks)) _new_size *= 2; new_array = ((_new_size ) > 0 ? ((uint8_t*)BrotliAllocate(((m)), (_new_size) * sizeof (uint8_t))) : ((void*)0)); if (!(!!0) && !(!!0) && split->types_alloc_size != 0) memcpy(new_array, split-> types, split->types_alloc_size * sizeof(uint8_t)); { BrotliFree (((m)), (split->types)); split->types = ((void*)0); }; split ->types = new_array; split->types_alloc_size = _new_size ; } }; | ||||||
363 | BROTLI_ENSURE_CAPACITY(m, uint32_t,{ if (split->lengths_alloc_size < (max_num_blocks)) { size_t _new_size = (split->lengths_alloc_size == 0) ? (max_num_blocks ) : split->lengths_alloc_size; uint32_t* new_array; while ( _new_size < (max_num_blocks)) _new_size *= 2; new_array = ( (_new_size) > 0 ? ((uint32_t*)BrotliAllocate(((m)), (_new_size ) * sizeof(uint32_t))) : ((void*)0)); if (!(!!0) && ! (!!0) && split->lengths_alloc_size != 0) memcpy(new_array , split->lengths, split->lengths_alloc_size * sizeof(uint32_t )); { BrotliFree(((m)), (split->lengths)); split->lengths = ((void*)0); }; split->lengths = new_array; split->lengths_alloc_size = _new_size; } } | ||||||
364 | split->lengths, split->lengths_alloc_size, max_num_blocks){ if (split->lengths_alloc_size < (max_num_blocks)) { size_t _new_size = (split->lengths_alloc_size == 0) ? (max_num_blocks ) : split->lengths_alloc_size; uint32_t* new_array; while ( _new_size < (max_num_blocks)) _new_size *= 2; new_array = ( (_new_size) > 0 ? ((uint32_t*)BrotliAllocate(((m)), (_new_size ) * sizeof(uint32_t))) : ((void*)0)); if (!(!!0) && ! (!!0) && split->lengths_alloc_size != 0) memcpy(new_array , split->lengths, split->lengths_alloc_size * sizeof(uint32_t )); { BrotliFree(((m)), (split->lengths)); split->lengths = ((void*)0); }; split->lengths = new_array; split->lengths_alloc_size = _new_size; } }; | ||||||
365 | if (BROTLI_IS_OOM(m)(!!0)) return; | ||||||
366 | split->num_blocks = max_num_blocks; | ||||||
367 | if (BROTLI_IS_OOM(m)(!!0)) return; | ||||||
368 | BROTLI_DCHECK(*histograms == 0); | ||||||
369 | *histograms_size = max_num_types * num_contexts; | ||||||
370 | *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size)((*histograms_size) > 0 ? ((HistogramLiteral*)BrotliAllocate ((m), (*histograms_size) * sizeof(HistogramLiteral))) : ((void *)0)); | ||||||
371 | self->histograms_ = *histograms; | ||||||
372 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(*histograms)(!!0)) return; | ||||||
373 | /* Clear only current histogram. */ | ||||||
374 | ClearHistogramsLiteral(&self->histograms_[0], num_contexts); | ||||||
375 | self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0; | ||||||
376 | } | ||||||
377 | |||||||
378 | /* Does either of three things: | ||||||
379 | (1) emits the current block with a new block type; | ||||||
380 | (2) emits the current block with the type of the second last block; | ||||||
381 | (3) merges the current block with the last block. */ | ||||||
382 | static void ContextBlockSplitterFinishBlock( | ||||||
383 | ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOLint is_final) { | ||||||
384 | BlockSplit* split = self->split_; | ||||||
385 | const size_t num_contexts = self->num_contexts_; | ||||||
386 | double* last_entropy = self->last_entropy_; | ||||||
387 | HistogramLiteral* histograms = self->histograms_; | ||||||
388 | |||||||
389 | if (self->block_size_ < self->min_block_size_) { | ||||||
390 | self->block_size_ = self->min_block_size_; | ||||||
391 | } | ||||||
392 | if (self->num_blocks_ == 0) { | ||||||
393 | size_t i; | ||||||
394 | /* Create first block. */ | ||||||
395 | split->lengths[0] = (uint32_t)self->block_size_; | ||||||
396 | split->types[0] = 0; | ||||||
397 | |||||||
398 | for (i = 0; i < num_contexts; ++i) { | ||||||
399 | last_entropy[i] = | ||||||
400 | BitsEntropy(histograms[i].data_, self->alphabet_size_); | ||||||
401 | last_entropy[num_contexts + i] = last_entropy[i]; | ||||||
402 | } | ||||||
403 | ++self->num_blocks_; | ||||||
404 | ++split->num_types; | ||||||
405 | self->curr_histogram_ix_ += num_contexts; | ||||||
406 | if (self->curr_histogram_ix_ < *self->histograms_size_) { | ||||||
407 | ClearHistogramsLiteral( | ||||||
408 | &self->histograms_[self->curr_histogram_ix_], self->num_contexts_); | ||||||
409 | } | ||||||
410 | self->block_size_ = 0; | ||||||
411 | } else if (self->block_size_ > 0) { | ||||||
412 | /* Try merging the set of histograms for the current block type with the | ||||||
413 | respective set of histograms for the last and second last block types. | ||||||
414 | Decide over the split based on the total reduction of entropy across | ||||||
415 | all contexts. */ | ||||||
416 | double entropy[BROTLI_MAX_STATIC_CONTEXTS13]; | ||||||
417 | HistogramLiteral* combined_histo = | ||||||
418 | BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts)((2 * num_contexts) > 0 ? ((HistogramLiteral*)BrotliAllocate ((m), (2 * num_contexts) * sizeof(HistogramLiteral))) : ((void *)0)); | ||||||
419 | double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS13]; | ||||||
420 | double diff[2] = { 0.0 }; | ||||||
421 | size_t i; | ||||||
422 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(combined_histo)(!!0)) return; | ||||||
423 | for (i = 0; i < num_contexts; ++i) { | ||||||
424 | size_t curr_histo_ix = self->curr_histogram_ix_ + i; | ||||||
425 | size_t j; | ||||||
426 | entropy[i] = BitsEntropy(histograms[curr_histo_ix].data_, | ||||||
427 | self->alphabet_size_); | ||||||
428 | for (j = 0; j < 2; ++j) { | ||||||
429 | size_t jx = j * num_contexts + i; | ||||||
430 | size_t last_histogram_ix = self->last_histogram_ix_[j] + i; | ||||||
431 | combined_histo[jx] = histograms[curr_histo_ix]; | ||||||
432 | HistogramAddHistogramLiteral(&combined_histo[jx], | ||||||
433 | &histograms[last_histogram_ix]); | ||||||
434 | combined_entropy[jx] = BitsEntropy( | ||||||
435 | &combined_histo[jx].data_[0], self->alphabet_size_); | ||||||
436 | diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx]; | ||||||
437 | } | ||||||
438 | } | ||||||
439 | |||||||
440 | if (split->num_types < self->max_block_types_ && | ||||||
441 | diff[0] > self->split_threshold_ && | ||||||
442 | diff[1] > self->split_threshold_) { | ||||||
443 | /* Create new block. */ | ||||||
444 | split->lengths[self->num_blocks_] = (uint32_t)self->block_size_; | ||||||
445 | split->types[self->num_blocks_] = (uint8_t)split->num_types; | ||||||
446 | self->last_histogram_ix_[1] = self->last_histogram_ix_[0]; | ||||||
447 | self->last_histogram_ix_[0] = split->num_types * num_contexts; | ||||||
448 | for (i = 0; i < num_contexts; ++i) { | ||||||
449 | last_entropy[num_contexts + i] = last_entropy[i]; | ||||||
450 | last_entropy[i] = entropy[i]; | ||||||
451 | } | ||||||
452 | ++self->num_blocks_; | ||||||
453 | ++split->num_types; | ||||||
454 | self->curr_histogram_ix_ += num_contexts; | ||||||
455 | if (self->curr_histogram_ix_ < *self->histograms_size_) { | ||||||
456 | ClearHistogramsLiteral( | ||||||
457 | &self->histograms_[self->curr_histogram_ix_], self->num_contexts_); | ||||||
458 | } | ||||||
459 | self->block_size_ = 0; | ||||||
460 | self->merge_last_count_ = 0; | ||||||
461 | self->target_block_size_ = self->min_block_size_; | ||||||
462 | } else if (diff[1] < diff[0] - 20.0) { | ||||||
463 | /* Combine this block with second last block. */ | ||||||
464 | split->lengths[self->num_blocks_] = (uint32_t)self->block_size_; | ||||||
465 | split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2]; | ||||||
466 | BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1){ size_t __brotli_swap_tmp = (self->last_histogram_ix_)[(0 )]; (self->last_histogram_ix_)[(0)] = (self->last_histogram_ix_ )[(1)]; (self->last_histogram_ix_)[(1)] = __brotli_swap_tmp ; }; | ||||||
467 | for (i = 0; i < num_contexts; ++i) { | ||||||
468 | histograms[self->last_histogram_ix_[0] + i] = | ||||||
469 | combined_histo[num_contexts + i]; | ||||||
470 | last_entropy[num_contexts + i] = last_entropy[i]; | ||||||
471 | last_entropy[i] = combined_entropy[num_contexts + i]; | ||||||
472 | HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]); | ||||||
473 | } | ||||||
474 | ++self->num_blocks_; | ||||||
475 | self->block_size_ = 0; | ||||||
476 | self->merge_last_count_ = 0; | ||||||
477 | self->target_block_size_ = self->min_block_size_; | ||||||
478 | } else { | ||||||
479 | /* Combine this block with last block. */ | ||||||
480 | split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_; | ||||||
481 | for (i = 0; i < num_contexts; ++i) { | ||||||
482 | histograms[self->last_histogram_ix_[0] + i] = combined_histo[i]; | ||||||
483 | last_entropy[i] = combined_entropy[i]; | ||||||
484 | if (split->num_types == 1) { | ||||||
485 | last_entropy[num_contexts + i] = last_entropy[i]; | ||||||
486 | } | ||||||
487 | HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]); | ||||||
488 | } | ||||||
489 | self->block_size_ = 0; | ||||||
490 | if (++self->merge_last_count_ > 1) { | ||||||
491 | self->target_block_size_ += self->min_block_size_; | ||||||
492 | } | ||||||
493 | } | ||||||
494 | BROTLI_FREE(m, combined_histo){ BrotliFree((m), (combined_histo)); combined_histo = ((void* )0); }; | ||||||
495 | } | ||||||
496 | if (is_final) { | ||||||
497 | *self->histograms_size_ = split->num_types * num_contexts; | ||||||
498 | split->num_blocks = self->num_blocks_; | ||||||
499 | } | ||||||
500 | } | ||||||
501 | |||||||
502 | /* Adds the next symbol to the current block type and context. When the | ||||||
503 | current block reaches the target size, decides on merging the block. */ | ||||||
504 | static void ContextBlockSplitterAddSymbol( | ||||||
505 | ContextBlockSplitter* self, MemoryManager* m, | ||||||
506 | size_t symbol, size_t context) { | ||||||
507 | HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context], | ||||||
508 | symbol); | ||||||
509 | ++self->block_size_; | ||||||
510 | if (self->block_size_ == self->target_block_size_) { | ||||||
511 | ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE0); | ||||||
512 | if (BROTLI_IS_OOM(m)(!!0)) return; | ||||||
513 | } | ||||||
514 | } | ||||||
515 | |||||||
516 | static void MapStaticContexts(MemoryManager* m, | ||||||
517 | size_t num_contexts, | ||||||
518 | const uint32_t* static_context_map, | ||||||
519 | MetaBlockSplit* mb) { | ||||||
520 | size_t i; | ||||||
521 | BROTLI_DCHECK(mb->literal_context_map == 0); | ||||||
522 | mb->literal_context_map_size = | ||||||
523 | mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS6; | ||||||
524 | mb->literal_context_map = | ||||||
525 | BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size)((mb->literal_context_map_size) > 0 ? ((uint32_t*)BrotliAllocate ((m), (mb->literal_context_map_size) * sizeof(uint32_t))) : ((void*)0)); | ||||||
526 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(mb->literal_context_map)(!!0)) return; | ||||||
527 | |||||||
528 | for (i = 0; i < mb->literal_split.num_types; ++i) { | ||||||
529 | uint32_t offset = (uint32_t)(i * num_contexts); | ||||||
530 | size_t j; | ||||||
531 | for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS6); ++j) { | ||||||
532 | mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS6) + j] = | ||||||
533 | offset + static_context_map[j]; | ||||||
534 | } | ||||||
535 | } | ||||||
536 | } | ||||||
537 | |||||||
538 | static BROTLI_INLINEinline __attribute__((__always_inline__)) void BrotliBuildMetaBlockGreedyInternal( | ||||||
539 | MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask, | ||||||
540 | uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut, | ||||||
541 | const size_t num_contexts, const uint32_t* static_context_map, | ||||||
542 | const Command* commands, size_t n_commands, MetaBlockSplit* mb) { | ||||||
543 | union { | ||||||
544 | BlockSplitterLiteral plain; | ||||||
545 | ContextBlockSplitter ctx; | ||||||
546 | } lit_blocks; | ||||||
547 | BlockSplitterCommand cmd_blocks; | ||||||
548 | BlockSplitterDistance dist_blocks; | ||||||
549 | size_t num_literals = 0; | ||||||
550 | size_t i; | ||||||
551 | for (i = 0; i < n_commands; ++i) { | ||||||
552 | num_literals += commands[i].insert_len_; | ||||||
553 | } | ||||||
554 | |||||||
555 | if (num_contexts
| ||||||
556 | InitBlockSplitterLiteral(m, &lit_blocks.plain, 256, 512, 400.0, | ||||||
557 | num_literals, &mb->literal_split, &mb->literal_histograms, | ||||||
558 | &mb->literal_histograms_size); | ||||||
559 | } else { | ||||||
560 | InitContextBlockSplitter(m, &lit_blocks.ctx, 256, num_contexts, 512, 400.0, | ||||||
561 | num_literals, &mb->literal_split, &mb->literal_histograms, | ||||||
562 | &mb->literal_histograms_size); | ||||||
563 | } | ||||||
564 | if (BROTLI_IS_OOM(m)(!!0)) return; | ||||||
565 | InitBlockSplitterCommand(m, &cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS704, 1024, | ||||||
566 | 500.0, n_commands, &mb->command_split, &mb->command_histograms, | ||||||
567 | &mb->command_histograms_size); | ||||||
568 | if (BROTLI_IS_OOM(m)(!!0)) return; | ||||||
569 | InitBlockSplitterDistance(m, &dist_blocks, 64, 512, 100.0, n_commands, | ||||||
570 | &mb->distance_split, &mb->distance_histograms, | ||||||
571 | &mb->distance_histograms_size); | ||||||
572 | if (BROTLI_IS_OOM(m)(!!0)) return; | ||||||
573 | |||||||
574 | for (i = 0; i < n_commands; ++i) { | ||||||
575 | const Command cmd = commands[i]; | ||||||
576 | size_t j; | ||||||
577 | BlockSplitterAddSymbolCommand(&cmd_blocks, cmd.cmd_prefix_); | ||||||
578 | for (j = cmd.insert_len_; j != 0; --j) { | ||||||
579 | uint8_t literal = ringbuffer[pos & mask]; | ||||||
580 | if (num_contexts == 1) { | ||||||
581 | BlockSplitterAddSymbolLiteral(&lit_blocks.plain, literal); | ||||||
582 | } else { | ||||||
583 | size_t context = | ||||||
584 | BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut)((literal_context_lut)[prev_byte] | ((literal_context_lut) + 256 )[prev_byte2]); | ||||||
585 | ContextBlockSplitterAddSymbol(&lit_blocks.ctx, m, literal, | ||||||
586 | static_context_map[context]); | ||||||
587 | if (BROTLI_IS_OOM(m)(!!0)) return; | ||||||
588 | } | ||||||
589 | prev_byte2 = prev_byte; | ||||||
590 | prev_byte = literal; | ||||||
591 | ++pos; | ||||||
592 | } | ||||||
593 | pos += CommandCopyLen(&cmd); | ||||||
594 | if (CommandCopyLen(&cmd)) { | ||||||
595 | prev_byte2 = ringbuffer[(pos - 2) & mask]; | ||||||
596 | prev_byte = ringbuffer[(pos - 1) & mask]; | ||||||
597 | if (cmd.cmd_prefix_ >= 128) { | ||||||
598 | BlockSplitterAddSymbolDistance(&dist_blocks, cmd.dist_prefix_ & 0x3FF); | ||||||
599 | } | ||||||
600 | } | ||||||
601 | } | ||||||
602 | |||||||
603 | if (num_contexts == 1) { | ||||||
604 | BlockSplitterFinishBlockLiteral( | ||||||
605 | &lit_blocks.plain, /* is_final = */ BROTLI_TRUE1); | ||||||
606 | } else { | ||||||
607 | ContextBlockSplitterFinishBlock( | ||||||
608 | &lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE1); | ||||||
609 | if (BROTLI_IS_OOM(m)(!!0)) return; | ||||||
610 | } | ||||||
611 | BlockSplitterFinishBlockCommand(&cmd_blocks, /* is_final = */ BROTLI_TRUE1); | ||||||
612 | BlockSplitterFinishBlockDistance(&dist_blocks, /* is_final = */ BROTLI_TRUE1); | ||||||
613 | |||||||
614 | if (num_contexts > 1) { | ||||||
615 | MapStaticContexts(m, num_contexts, static_context_map, mb); | ||||||
616 | } | ||||||
617 | } | ||||||
618 | |||||||
619 | void BrotliBuildMetaBlockGreedy(MemoryManager* m, | ||||||
620 | const uint8_t* ringbuffer, | ||||||
621 | size_t pos, | ||||||
622 | size_t mask, | ||||||
623 | uint8_t prev_byte, | ||||||
624 | uint8_t prev_byte2, | ||||||
625 | ContextLut literal_context_lut, | ||||||
626 | size_t num_contexts, | ||||||
627 | const uint32_t* static_context_map, | ||||||
628 | const Command* commands, | ||||||
629 | size_t n_commands, | ||||||
630 | MetaBlockSplit* mb) { | ||||||
631 | if (num_contexts == 1) { | ||||||
| |||||||
632 | BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte, | ||||||
633 | prev_byte2, literal_context_lut, 1, NULL((void*)0), commands, n_commands, mb); | ||||||
634 | } else { | ||||||
635 | BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte, | ||||||
636 | prev_byte2, literal_context_lut, num_contexts, static_context_map, | ||||||
637 | commands, n_commands, mb); | ||||||
638 | } | ||||||
639 | } | ||||||
640 | |||||||
641 | void BrotliOptimizeHistograms(uint32_t num_distance_codes, | ||||||
642 | MetaBlockSplit* mb) { | ||||||
643 | uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS704]; | ||||||
644 | size_t i; | ||||||
645 | for (i = 0; i < mb->literal_histograms_size; ++i) { | ||||||
646 | BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_, | ||||||
647 | good_for_rle); | ||||||
648 | } | ||||||
649 | for (i = 0; i < mb->command_histograms_size; ++i) { | ||||||
650 | BrotliOptimizeHuffmanCountsForRle(BROTLI_NUM_COMMAND_SYMBOLS704, | ||||||
651 | mb->command_histograms[i].data_, | ||||||
652 | good_for_rle); | ||||||
653 | } | ||||||
654 | for (i = 0; i < mb->distance_histograms_size; ++i) { | ||||||
655 | BrotliOptimizeHuffmanCountsForRle(num_distance_codes, | ||||||
656 | mb->distance_histograms[i].data_, | ||||||
657 | good_for_rle); | ||||||
658 | } | ||||||
659 | } | ||||||
660 | |||||||
661 | #if defined(__cplusplus) || defined(c_plusplus) | ||||||
662 | } /* extern "C" */ | ||||||
663 | #endif |
1 | /* NOLINT(build/header_guard) */ |
2 | /* Copyright 2015 Google Inc. All Rights Reserved. |
3 | |
4 | Distributed under MIT license. |
5 | See file LICENSE for detail or copy at https://opensource.org/licenses/MIT |
6 | */ |
7 | |
8 | /* template parameters: FN */ |
9 | |
10 | #define HistogramType FN(Histogram) |
11 | |
12 | /* Greedy block splitter for one block category (literal, command or distance). |
13 | */ |
14 | typedef struct FN(BlockSplitter) { |
15 | /* Alphabet size of particular block category. */ |
16 | size_t alphabet_size_; |
17 | /* We collect at least this many symbols for each block. */ |
18 | size_t min_block_size_; |
19 | /* We merge histograms A and B if |
20 | entropy(A+B) < entropy(A) + entropy(B) + split_threshold_, |
21 | where A is the current histogram and B is the histogram of the last or the |
22 | second last block type. */ |
23 | double split_threshold_; |
24 | |
25 | size_t num_blocks_; |
26 | BlockSplit* split_; /* not owned */ |
27 | HistogramType* histograms_; /* not owned */ |
28 | size_t* histograms_size_; /* not owned */ |
29 | |
30 | /* The number of symbols that we want to collect before deciding on whether |
31 | or not to merge the block with a previous one or emit a new block. */ |
32 | size_t target_block_size_; |
33 | /* The number of symbols in the current histogram. */ |
34 | size_t block_size_; |
35 | /* Offset of the current histogram. */ |
36 | size_t curr_histogram_ix_; |
37 | /* Offset of the histograms of the previous two block types. */ |
38 | size_t last_histogram_ix_[2]; |
39 | /* Entropy of the previous two block types. */ |
40 | double last_entropy_[2]; |
41 | /* The number of times we merged the current block with the last one. */ |
42 | size_t merge_last_count_; |
43 | } FN(BlockSplitter); |
44 | |
45 | static void FN(InitBlockSplitter)( |
46 | MemoryManager* m, FN(BlockSplitter)* self, size_t alphabet_size, |
47 | size_t min_block_size, double split_threshold, size_t num_symbols, |
48 | BlockSplit* split, HistogramType** histograms, size_t* histograms_size) { |
49 | size_t max_num_blocks = num_symbols / min_block_size + 1; |
50 | /* We have to allocate one more histogram than the maximum number of block |
51 | types for the current histogram when the meta-block is too big. */ |
52 | size_t max_num_types = |
53 | BROTLI_MIN(size_t, max_num_blocks, BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + 1)(brotli_min_size_t((max_num_blocks), (256 + 1))); |
54 | self->alphabet_size_ = alphabet_size; |
55 | self->min_block_size_ = min_block_size; |
56 | self->split_threshold_ = split_threshold; |
57 | self->num_blocks_ = 0; |
58 | self->split_ = split; |
59 | self->histograms_size_ = histograms_size; |
60 | self->target_block_size_ = min_block_size; |
61 | self->block_size_ = 0; |
62 | self->curr_histogram_ix_ = 0; |
63 | self->merge_last_count_ = 0; |
64 | BROTLI_ENSURE_CAPACITY(m, uint8_t,{ if (split->types_alloc_size < (max_num_blocks)) { size_t _new_size = (split->types_alloc_size == 0) ? (max_num_blocks ) : split->types_alloc_size; uint8_t* new_array; while (_new_size < (max_num_blocks)) _new_size *= 2; new_array = ((_new_size ) > 0 ? ((uint8_t*)BrotliAllocate(((m)), (_new_size) * sizeof (uint8_t))) : ((void*)0)); if (!(!!0) && !(!!0) && split->types_alloc_size != 0) memcpy(new_array, split-> types, split->types_alloc_size * sizeof(uint8_t)); { BrotliFree (((m)), (split->types)); split->types = ((void*)0); }; split ->types = new_array; split->types_alloc_size = _new_size ; } } |
65 | split->types, split->types_alloc_size, max_num_blocks){ if (split->types_alloc_size < (max_num_blocks)) { size_t _new_size = (split->types_alloc_size == 0) ? (max_num_blocks ) : split->types_alloc_size; uint8_t* new_array; while (_new_size < (max_num_blocks)) _new_size *= 2; new_array = ((_new_size ) > 0 ? ((uint8_t*)BrotliAllocate(((m)), (_new_size) * sizeof (uint8_t))) : ((void*)0)); if (!(!!0) && !(!!0) && split->types_alloc_size != 0) memcpy(new_array, split-> types, split->types_alloc_size * sizeof(uint8_t)); { BrotliFree (((m)), (split->types)); split->types = ((void*)0); }; split ->types = new_array; split->types_alloc_size = _new_size ; } }; |
66 | BROTLI_ENSURE_CAPACITY(m, uint32_t,{ if (split->lengths_alloc_size < (max_num_blocks)) { size_t _new_size = (split->lengths_alloc_size == 0) ? (max_num_blocks ) : split->lengths_alloc_size; uint32_t* new_array; while ( _new_size < (max_num_blocks)) _new_size *= 2; new_array = ( (_new_size) > 0 ? ((uint32_t*)BrotliAllocate(((m)), (_new_size ) * sizeof(uint32_t))) : ((void*)0)); if (!(!!0) && ! (!!0) && split->lengths_alloc_size != 0) memcpy(new_array , split->lengths, split->lengths_alloc_size * sizeof(uint32_t )); { BrotliFree(((m)), (split->lengths)); split->lengths = ((void*)0); }; split->lengths = new_array; split->lengths_alloc_size = _new_size; } } |
67 | split->lengths, split->lengths_alloc_size, max_num_blocks){ if (split->lengths_alloc_size < (max_num_blocks)) { size_t _new_size = (split->lengths_alloc_size == 0) ? (max_num_blocks ) : split->lengths_alloc_size; uint32_t* new_array; while ( _new_size < (max_num_blocks)) _new_size *= 2; new_array = ( (_new_size) > 0 ? ((uint32_t*)BrotliAllocate(((m)), (_new_size ) * sizeof(uint32_t))) : ((void*)0)); if (!(!!0) && ! (!!0) && split->lengths_alloc_size != 0) memcpy(new_array , split->lengths, split->lengths_alloc_size * sizeof(uint32_t )); { BrotliFree(((m)), (split->lengths)); split->lengths = ((void*)0); }; split->lengths = new_array; split->lengths_alloc_size = _new_size; } }; |
68 | if (BROTLI_IS_OOM(m)(!!0)) return; |
69 | self->split_->num_blocks = max_num_blocks; |
70 | BROTLI_DCHECK(*histograms == 0); |
71 | *histograms_size = max_num_types; |
72 | *histograms = BROTLI_ALLOC(m, HistogramType, *histograms_size)((*histograms_size) > 0 ? ((HistogramType*)BrotliAllocate( (m), (*histograms_size) * sizeof(HistogramType))) : ((void*)0 )); |
73 | self->histograms_ = *histograms; |
74 | if (BROTLI_IS_OOM(m)(!!0) || BROTLI_IS_NULL(*histograms)(!!0)) return; |
75 | /* Clear only current histogram. */ |
76 | FN(HistogramClear)(&self->histograms_[0]); |
77 | self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0; |
78 | } |
79 | |
80 | /* Does either of three things: |
81 | (1) emits the current block with a new block type; |
82 | (2) emits the current block with the type of the second last block; |
83 | (3) merges the current block with the last block. */ |
84 | static void FN(BlockSplitterFinishBlock)( |
85 | FN(BlockSplitter)* self, BROTLI_BOOLint is_final) { |
86 | BlockSplit* split = self->split_; |
87 | double* last_entropy = self->last_entropy_; |
88 | HistogramType* histograms = self->histograms_; |
89 | self->block_size_ = |
90 | BROTLI_MAX(size_t, self->block_size_, self->min_block_size_)(brotli_max_size_t((self->block_size_), (self->min_block_size_ ))); |
91 | if (self->num_blocks_ == 0) { |
92 | /* Create first block. */ |
93 | split->lengths[0] = (uint32_t)self->block_size_; |
94 | split->types[0] = 0; |
95 | last_entropy[0] = |
96 | BitsEntropy(histograms[0].data_, self->alphabet_size_); |
97 | last_entropy[1] = last_entropy[0]; |
98 | ++self->num_blocks_; |
99 | ++split->num_types; |
100 | ++self->curr_histogram_ix_; |
101 | if (self->curr_histogram_ix_ < *self->histograms_size_) |
102 | FN(HistogramClear)(&histograms[self->curr_histogram_ix_]); |
103 | self->block_size_ = 0; |
104 | } else if (self->block_size_ > 0) { |
105 | double entropy = BitsEntropy(histograms[self->curr_histogram_ix_].data_, |
106 | self->alphabet_size_); |
107 | HistogramType combined_histo[2]; |
108 | double combined_entropy[2]; |
109 | double diff[2]; |
110 | size_t j; |
111 | for (j = 0; j < 2; ++j) { |
112 | size_t last_histogram_ix = self->last_histogram_ix_[j]; |
113 | combined_histo[j] = histograms[self->curr_histogram_ix_]; |
114 | FN(HistogramAddHistogram)(&combined_histo[j], |
115 | &histograms[last_histogram_ix]); |
116 | combined_entropy[j] = BitsEntropy( |
117 | &combined_histo[j].data_[0], self->alphabet_size_); |
118 | diff[j] = combined_entropy[j] - entropy - last_entropy[j]; |
119 | } |
120 | |
121 | if (split->num_types < BROTLI_MAX_NUMBER_OF_BLOCK_TYPES256 && |
122 | diff[0] > self->split_threshold_ && |
123 | diff[1] > self->split_threshold_) { |
124 | /* Create new block. */ |
125 | split->lengths[self->num_blocks_] = (uint32_t)self->block_size_; |
126 | split->types[self->num_blocks_] = (uint8_t)split->num_types; |
127 | self->last_histogram_ix_[1] = self->last_histogram_ix_[0]; |
128 | self->last_histogram_ix_[0] = (uint8_t)split->num_types; |
129 | last_entropy[1] = last_entropy[0]; |
130 | last_entropy[0] = entropy; |
131 | ++self->num_blocks_; |
132 | ++split->num_types; |
133 | ++self->curr_histogram_ix_; |
134 | if (self->curr_histogram_ix_ < *self->histograms_size_) |
135 | FN(HistogramClear)(&histograms[self->curr_histogram_ix_]); |
136 | self->block_size_ = 0; |
137 | self->merge_last_count_ = 0; |
138 | self->target_block_size_ = self->min_block_size_; |
139 | } else if (diff[1] < diff[0] - 20.0) { |
140 | /* Combine this block with second last block. */ |
141 | split->lengths[self->num_blocks_] = (uint32_t)self->block_size_; |
142 | split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2]; |
143 | BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1){ size_t __brotli_swap_tmp = (self->last_histogram_ix_)[(0 )]; (self->last_histogram_ix_)[(0)] = (self->last_histogram_ix_ )[(1)]; (self->last_histogram_ix_)[(1)] = __brotli_swap_tmp ; }; |
144 | histograms[self->last_histogram_ix_[0]] = combined_histo[1]; |
145 | last_entropy[1] = last_entropy[0]; |
146 | last_entropy[0] = combined_entropy[1]; |
147 | ++self->num_blocks_; |
148 | self->block_size_ = 0; |
149 | FN(HistogramClear)(&histograms[self->curr_histogram_ix_]); |
150 | self->merge_last_count_ = 0; |
151 | self->target_block_size_ = self->min_block_size_; |
152 | } else { |
153 | /* Combine this block with last block. */ |
154 | split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_; |
155 | histograms[self->last_histogram_ix_[0]] = combined_histo[0]; |
156 | last_entropy[0] = combined_entropy[0]; |
157 | if (split->num_types == 1) { |
158 | last_entropy[1] = last_entropy[0]; |
159 | } |
160 | self->block_size_ = 0; |
161 | FN(HistogramClear)(&histograms[self->curr_histogram_ix_]); |
162 | if (++self->merge_last_count_ > 1) { |
163 | self->target_block_size_ += self->min_block_size_; |
164 | } |
165 | } |
166 | } |
167 | if (is_final) { |
168 | *self->histograms_size_ = split->num_types; |
169 | split->num_blocks = self->num_blocks_; |
170 | } |
171 | } |
172 | |
173 | /* Adds the next symbol to the current histogram. When the current histogram |
174 | reaches the target size, decides on merging the block. */ |
175 | static void FN(BlockSplitterAddSymbol)(FN(BlockSplitter)* self, size_t symbol) { |
176 | FN(HistogramAdd)(&self->histograms_[self->curr_histogram_ix_], symbol); |
177 | ++self->block_size_; |
178 | if (self->block_size_ == self->target_block_size_) { |
179 | FN(BlockSplitterFinishBlock)(self, /* is_final = */ BROTLI_FALSE0); |
180 | } |
181 | } |
182 | |
183 | #undef HistogramType |
1 | /* NOLINT(build/header_guard) */ | |||
2 | /* Copyright 2013 Google Inc. All Rights Reserved. | |||
3 | ||||
4 | Distributed under MIT license. | |||
5 | See file LICENSE for detail or copy at https://opensource.org/licenses/MIT | |||
6 | */ | |||
7 | ||||
8 | /* template parameters: Histogram, DATA_SIZE, DataType */ | |||
9 | ||||
10 | /* A simple container for histograms of data in blocks. */ | |||
11 | ||||
12 | typedef struct FN(Histogram) { | |||
13 | uint32_t data_[DATA_SIZE]; | |||
14 | size_t total_count_; | |||
15 | double bit_cost_; | |||
16 | } FN(Histogram); | |||
17 | ||||
18 | static BROTLI_INLINEinline __attribute__((__always_inline__)) void FN(HistogramClear)(FN(Histogram)* self) { | |||
19 | memset(self->data_, 0, sizeof(self->data_)); | |||
| ||||
20 | self->total_count_ = 0; | |||
21 | self->bit_cost_ = HUGE_VAL(__builtin_huge_val ()); | |||
22 | } | |||
23 | ||||
24 | static BROTLI_INLINEinline __attribute__((__always_inline__)) void FN(ClearHistograms)( | |||
25 | FN(Histogram)* array, size_t length) { | |||
26 | size_t i; | |||
27 | for (i = 0; i < length; ++i) FN(HistogramClear)(array + i); | |||
28 | } | |||
29 | ||||
30 | static BROTLI_INLINEinline __attribute__((__always_inline__)) void FN(HistogramAdd)(FN(Histogram)* self, size_t val) { | |||
31 | ++self->data_[val]; | |||
32 | ++self->total_count_; | |||
33 | } | |||
34 | ||||
35 | static BROTLI_INLINEinline __attribute__((__always_inline__)) void FN(HistogramAddVector)(FN(Histogram)* self, | |||
36 | const DataType* p, size_t n) { | |||
37 | self->total_count_ += n; | |||
38 | n += 1; | |||
39 | while (--n) ++self->data_[*p++]; | |||
40 | } | |||
41 | ||||
42 | static BROTLI_INLINEinline __attribute__((__always_inline__)) void FN(HistogramAddHistogram)(FN(Histogram)* self, | |||
43 | const FN(Histogram)* v) { | |||
44 | size_t i; | |||
45 | self->total_count_ += v->total_count_; | |||
46 | for (i = 0; i < DATA_SIZE; ++i) { | |||
47 | self->data_[i] += v->data_[i]; | |||
48 | } | |||
49 | } | |||
50 | ||||
51 | static BROTLI_INLINEinline __attribute__((__always_inline__)) size_t FN(HistogramDataSize)(void) { return DATA_SIZE; } |