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