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