Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/brotli/c/enc/metablock.c
Line
Count
Source
1
/* Copyright 2015 Google Inc. All Rights Reserved.
2
3
   Distributed under MIT license.
4
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5
*/
6
7
/* Algorithms for distributing the literals and commands of a metablock between
8
   block types and contexts. */
9
10
#include "metablock.h"
11
12
#include "bit_cost.h"
13
#include "block_splitter.h"
14
#include "cluster.h"
15
#include "command.h"
16
#include "entropy_encode.h"
17
#include "hash.h"
18
#include "histogram.h"
19
#include "memory.h"
20
#include "params.h"
21
#include "prefix.h"
22
#include "../common/constants.h"
23
#include "../common/context.h"
24
#include "../common/platform.h"
25
26
#if defined(__cplusplus) || defined(c_plusplus)
27
extern "C" {
28
#endif
29
30
static void ForceBase64LiteralSplits(MemoryManager* m, BlockSplit* split,
31
                                     const Base64Region* base64_regions,
32
                                     size_t num_base64_regions,
33
                                     size_t last_flush_pos,
34
0
                                     MetaBlockSplit* mb) {
35
0
  size_t r;
36
  /* Each base64 region can split an existing block into at most 3 blocks
37
     (adding 2 new blocks). In the worst case, every base64 region splits
38
     a different block, increasing the number of blocks by 2 *
39
     num_base64_regions. We add 1 extra block as a safety margin. */
40
0
  size_t new_alloc_size = split->num_blocks + num_base64_regions * 2 + 1;
41
0
  uint8_t* new_types = BROTLI_ALLOC(m, uint8_t, new_alloc_size);
42
0
  uint32_t* new_lengths = BROTLI_ALLOC(m, uint32_t, new_alloc_size);
43
0
  size_t new_num_blocks = 0;
44
0
  size_t curr_offset = 0;
45
0
  size_t block_idx = 0;
46
0
  uint8_t base64_type_id;
47
48
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_types) ||
49
0
      BROTLI_IS_NULL(new_lengths)) {
50
0
    return;
51
0
  }
52
53
0
  memset(mb->literal_is_base64, 0, sizeof(mb->literal_is_base64));
54
0
  base64_type_id = (uint8_t)split->num_types;
55
0
  mb->literal_is_base64[base64_type_id >> 3] |=
56
0
      (uint8_t)(1u << (base64_type_id & 7));
57
58
0
  for (block_idx = 0; block_idx < split->num_blocks; ++block_idx) {
59
0
    uint32_t block_len = split->lengths[block_idx];
60
0
    uint8_t block_type = split->types[block_idx];
61
0
    size_t block_start = curr_offset;
62
0
    size_t block_end = curr_offset + block_len;
63
64
0
    BROTLI_BOOL intersected = BROTLI_FALSE;
65
0
    for (r = 0; r < num_base64_regions; ++r) {
66
0
      size_t b64_start = base64_regions[r].start_literal_pos - last_flush_pos;
67
0
      size_t b64_end = b64_start + base64_regions[r].length;
68
69
0
      if (b64_start < block_end && b64_end > block_start) {
70
0
        size_t intersect_start;
71
0
        size_t intersect_end;
72
0
        if (b64_start > block_start) {
73
0
          new_types[new_num_blocks] = block_type;
74
0
          new_lengths[new_num_blocks] = (uint32_t)(b64_start - block_start);
75
0
          new_num_blocks++;
76
0
        }
77
0
        intersect_start = BROTLI_MAX(size_t, block_start, b64_start);
78
0
        intersect_end = BROTLI_MIN(size_t, block_end, b64_end);
79
0
        new_types[new_num_blocks] = base64_type_id;
80
0
        new_lengths[new_num_blocks] =
81
0
            (uint32_t)(intersect_end - intersect_start);
82
0
        new_num_blocks++;
83
84
0
        if (b64_end < block_end) {
85
0
          block_start = b64_end;
86
0
          block_len = (uint32_t)(block_end - b64_end);
87
0
          continue;
88
0
        } else {
89
0
          block_len = 0;
90
0
          intersected = BROTLI_TRUE;
91
0
          break;
92
0
        }
93
0
      }
94
0
    }
95
96
0
    if (!intersected && block_len > 0) {
97
0
      new_types[new_num_blocks] = block_type;
98
0
      new_lengths[new_num_blocks] = block_len;
99
0
      new_num_blocks++;
100
0
    }
101
0
    curr_offset = block_end;
102
0
  }
103
104
0
  BROTLI_FREE(m, split->types);
105
0
  BROTLI_FREE(m, split->lengths);
106
0
  split->types = new_types;
107
0
  split->lengths = new_lengths;
108
0
  split->num_blocks = new_num_blocks;
109
0
  split->num_types++;
110
0
}
111
112
0
static void AppendBase64Histogram(MemoryManager* m, MetaBlockSplit* mb) {
113
0
  size_t base64_type_id = mb->literal_split.num_types - 1;
114
0
  size_t b64_histo_id = mb->literal_histograms_size;
115
0
  size_t new_context_map_size =
116
0
      mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
117
0
  HistogramLiteral* new_histos =
118
0
      BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size + 1);
119
0
  uint32_t* new_context_map =
120
0
      BROTLI_ALLOC(m, uint32_t, new_context_map_size);
121
0
  size_t i;
122
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_histos) ||
123
0
      BROTLI_IS_NULL(new_context_map)) {
124
0
    BROTLI_FREE(m, new_histos);
125
0
    BROTLI_FREE(m, new_context_map);
126
0
    return;
127
0
  }
128
0
  memcpy(new_histos, mb->literal_histograms,
129
0
         mb->literal_histograms_size * sizeof(HistogramLiteral));
130
0
  BROTLI_FREE(m, mb->literal_histograms);
131
0
  mb->literal_histograms = new_histos;
132
0
  HistogramClearLiteral(&mb->literal_histograms[b64_histo_id]);
133
0
  mb->literal_histograms_size++;
134
135
0
  if (mb->literal_context_map != NULL) {
136
0
    memcpy(new_context_map, mb->literal_context_map,
137
0
           mb->literal_context_map_size * sizeof(uint32_t));
138
0
    BROTLI_FREE(m, mb->literal_context_map);
139
0
  } else {
140
    /* If context map was NULL (num_contexts == 1), initialize preceding types */
141
0
    size_t t;
142
0
    for (t = 0; t < base64_type_id; ++t) {
143
0
      for (i = 0; i < 64; ++i) {
144
0
        new_context_map[(t << 6) + i] = (uint32_t)t;
145
0
      }
146
0
    }
147
0
  }
148
0
  mb->literal_context_map = new_context_map;
149
0
  mb->literal_context_map_size = new_context_map_size;
150
0
  for (i = 0; i < 64; ++i) {
151
0
    mb->literal_context_map[(base64_type_id << 6) + i] = (uint32_t)b64_histo_id;
152
0
  }
153
0
}
154
155
static void MapBase64RegionsToLiteralPositions(
156
    const Command* commands, size_t num_commands, size_t last_flush_pos,
157
    const Base64Region* in_regions, size_t num_in_regions,
158
0
    Base64Region* out_regions) {
159
0
  size_t r;
160
0
  for (r = 0; r < num_in_regions; ++r) {
161
0
    size_t target_ring_pos = in_regions[r].start_literal_pos;
162
0
    size_t curr_ring_pos = last_flush_pos;
163
0
    size_t curr_lit_pos = 0;
164
0
    size_t i;
165
0
    for (i = 0; i < num_commands; ++i) {
166
0
      const Command cmd = commands[i];
167
0
      if (curr_ring_pos + cmd.insert_len_ >= target_ring_pos) {
168
0
        size_t offset = target_ring_pos > curr_ring_pos ? target_ring_pos - curr_ring_pos : 0;
169
0
        curr_lit_pos += offset;
170
0
        break;
171
0
      }
172
0
      curr_lit_pos += cmd.insert_len_;
173
0
      curr_ring_pos += cmd.insert_len_ + CommandCopyLen(&cmd);
174
0
    }
175
0
    out_regions[r].start_literal_pos = curr_lit_pos;
176
0
    out_regions[r].length = in_regions[r].length;
177
0
  }
178
0
}
179
180
void BrotliInitDistanceParams(BrotliDistanceParams* dist_params,
181
0
    uint32_t npostfix, uint32_t ndirect, BROTLI_BOOL large_window) {
182
0
  uint32_t alphabet_size_max;
183
0
  uint32_t alphabet_size_limit;
184
0
  uint32_t max_distance;
185
186
0
  dist_params->distance_postfix_bits = npostfix;
187
0
  dist_params->num_direct_distance_codes = ndirect;
188
189
0
  alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
190
0
      npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
191
0
  alphabet_size_limit = alphabet_size_max;
192
0
  max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) -
193
0
      (1U << (npostfix + 2));
194
195
0
  if (large_window) {
196
0
    BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
197
0
        BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
198
0
    alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
199
0
        npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
200
0
    alphabet_size_limit = limit.max_alphabet_size;
201
0
    max_distance = limit.max_distance;
202
0
  }
203
204
0
  dist_params->alphabet_size_max = alphabet_size_max;
205
0
  dist_params->alphabet_size_limit = alphabet_size_limit;
206
0
  dist_params->max_distance = max_distance;
207
0
}
208
209
static void RecomputeDistancePrefixes(Command* cmds,
210
                                      size_t num_commands,
211
                                      const BrotliDistanceParams* orig_params,
212
0
                                      const BrotliDistanceParams* new_params) {
213
0
  size_t i;
214
215
0
  if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
216
0
      orig_params->num_direct_distance_codes ==
217
0
      new_params->num_direct_distance_codes) {
218
0
    return;
219
0
  }
220
221
0
  for (i = 0; i < num_commands; ++i) {
222
0
    Command* cmd = &cmds[i];
223
0
    if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
224
0
      PrefixEncodeCopyDistance(CommandRestoreDistanceCode(cmd, orig_params),
225
0
                               new_params->num_direct_distance_codes,
226
0
                               new_params->distance_postfix_bits,
227
0
                               &cmd->dist_prefix_,
228
0
                               &cmd->dist_extra_);
229
0
    }
230
0
  }
231
0
}
232
233
static BROTLI_BOOL ComputeDistanceCost(const Command* cmds,
234
                                       size_t num_commands,
235
                                       const BrotliDistanceParams* orig_params,
236
                                       const BrotliDistanceParams* new_params,
237
                                       double* cost,
238
0
                                       HistogramDistance* tmp) {
239
0
  size_t i;
240
0
  BROTLI_BOOL equal_params = BROTLI_FALSE;
241
0
  uint16_t dist_prefix;
242
0
  uint32_t dist_extra;
243
0
  double extra_bits = 0.0;
244
0
  HistogramClearDistance(tmp);
245
246
0
  if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
247
0
      orig_params->num_direct_distance_codes ==
248
0
      new_params->num_direct_distance_codes) {
249
0
    equal_params = BROTLI_TRUE;
250
0
  }
251
252
0
  for (i = 0; i < num_commands; i++) {
253
0
    const Command* cmd = &cmds[i];
254
0
    if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
255
0
      if (equal_params) {
256
0
        dist_prefix = cmd->dist_prefix_;
257
0
      } else {
258
0
        uint32_t distance = CommandRestoreDistanceCode(cmd, orig_params);
259
0
        if (distance > new_params->max_distance) {
260
0
          return BROTLI_FALSE;
261
0
        }
262
0
        PrefixEncodeCopyDistance(distance,
263
0
                                 new_params->num_direct_distance_codes,
264
0
                                 new_params->distance_postfix_bits,
265
0
                                 &dist_prefix,
266
0
                                 &dist_extra);
267
0
      }
268
0
      HistogramAddDistance(tmp, dist_prefix & 0x3FF);
269
0
      extra_bits += dist_prefix >> 10;
270
0
    }
271
0
  }
272
273
0
  *cost = BrotliPopulationCostDistance(tmp) + extra_bits;
274
0
  return BROTLI_TRUE;
275
0
}
276
277
void BrotliBuildMetaBlock(MemoryManager* m, const uint8_t* ringbuffer,
278
                          const size_t pos, const size_t mask,
279
                          const Base64Region* base64_regions,
280
                          size_t num_base64_regions,
281
                          BrotliEncoderParams* params, uint8_t prev_byte,
282
                          uint8_t prev_byte2, Command* cmds,
283
                          size_t num_commands, ContextType literal_context_mode,
284
0
                          MetaBlockSplit* mb) {
285
  /* Histogram ids need to fit in one byte. */
286
0
  static const size_t kMaxNumberOfHistograms = 256;
287
0
  HistogramDistance* distance_histograms;
288
0
  HistogramLiteral* literal_histograms;
289
0
  ContextType* literal_context_modes = NULL;
290
0
  size_t literal_histograms_size;
291
0
  size_t distance_histograms_size;
292
0
  size_t i;
293
0
  size_t literal_context_multiplier = 1;
294
0
  uint32_t npostfix;
295
0
  uint32_t ndirect_msb = 0;
296
0
  BROTLI_BOOL check_orig = BROTLI_TRUE;
297
0
  double best_dist_cost = 1e99;
298
0
  BrotliDistanceParams orig_params = params->dist;
299
0
  BrotliDistanceParams new_params = params->dist;
300
0
  HistogramDistance* tmp = BROTLI_ALLOC(m, HistogramDistance, 1);
301
302
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return;
303
304
0
  for (npostfix = 0; npostfix <= BROTLI_MAX_NPOSTFIX; npostfix++) {
305
0
    for (; ndirect_msb < 16; ndirect_msb++) {
306
0
      uint32_t ndirect = ndirect_msb << npostfix;
307
0
      BROTLI_BOOL skip;
308
0
      double dist_cost;
309
0
      BrotliInitDistanceParams(&new_params, npostfix, ndirect,
310
0
                               params->large_window);
311
0
      if (npostfix == orig_params.distance_postfix_bits &&
312
0
          ndirect == orig_params.num_direct_distance_codes) {
313
0
        check_orig = BROTLI_FALSE;
314
0
      }
315
0
      skip = !ComputeDistanceCost(
316
0
          cmds, num_commands, &orig_params, &new_params, &dist_cost, tmp);
317
0
      if (skip || (dist_cost > best_dist_cost)) {
318
0
        break;
319
0
      }
320
0
      best_dist_cost = dist_cost;
321
0
      params->dist = new_params;
322
0
    }
323
0
    if (ndirect_msb > 0) ndirect_msb--;
324
0
    ndirect_msb /= 2;
325
0
  }
326
0
  if (check_orig) {
327
0
    double dist_cost;
328
0
    ComputeDistanceCost(cmds, num_commands, &orig_params, &orig_params,
329
0
                        &dist_cost, tmp);
330
0
    if (dist_cost < best_dist_cost) {
331
      /* NB: currently unused; uncomment when more param tuning is added. */
332
      /* best_dist_cost = dist_cost; */
333
0
      params->dist = orig_params;
334
0
    }
335
0
  }
336
0
  BROTLI_FREE(m, tmp);
337
0
  RecomputeDistancePrefixes(cmds, num_commands, &orig_params, &params->dist);
338
339
0
  BrotliSplitBlock(m, cmds, num_commands,
340
0
                   ringbuffer, pos, mask, params,
341
0
                   &mb->literal_split,
342
0
                   &mb->command_split,
343
0
                   &mb->distance_split);
344
0
  if (BROTLI_IS_OOM(m)) return;
345
346
0
  if (!params->disable_literal_context_modeling) {
347
0
    literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
348
0
    literal_context_modes =
349
0
        BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
350
0
    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_context_modes)) return;
351
0
    for (i = 0; i < mb->literal_split.num_types; ++i) {
352
0
      literal_context_modes[i] = literal_context_mode;
353
0
    }
354
0
  }
355
356
0
  literal_histograms_size =
357
0
      mb->literal_split.num_types * literal_context_multiplier;
358
0
  literal_histograms =
359
0
      BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
360
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_histograms)) return;
361
0
  ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
362
363
0
  distance_histograms_size =
364
0
      mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
365
0
  distance_histograms =
366
0
      BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
367
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_histograms)) return;
368
0
  ClearHistogramsDistance(distance_histograms, distance_histograms_size);
369
370
0
  BROTLI_DCHECK(mb->command_histograms == 0);
371
0
  mb->command_histograms_size = mb->command_split.num_types;
372
0
  mb->command_histograms =
373
0
      BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
374
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->command_histograms)) return;
375
0
  ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
376
377
0
  BrotliBuildHistogramsWithContext(cmds, num_commands,
378
0
      &mb->literal_split, &mb->command_split, &mb->distance_split,
379
0
      ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes,
380
0
      literal_histograms, mb->command_histograms, distance_histograms);
381
0
  BROTLI_FREE(m, literal_context_modes);
382
383
0
  BROTLI_DCHECK(mb->literal_context_map == 0);
384
0
  mb->literal_context_map_size =
385
0
      mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
386
0
  mb->literal_context_map =
387
0
      BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
388
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
389
390
0
  BROTLI_DCHECK(mb->literal_histograms == 0);
391
0
  mb->literal_histograms_size = mb->literal_context_map_size;
392
0
  mb->literal_histograms =
393
0
      BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
394
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_histograms)) return;
395
396
0
  BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
397
0
      kMaxNumberOfHistograms, mb->literal_histograms,
398
0
      &mb->literal_histograms_size, mb->literal_context_map);
399
0
  if (BROTLI_IS_OOM(m)) return;
400
0
  BROTLI_FREE(m, literal_histograms);
401
402
0
  if (params->disable_literal_context_modeling) {
403
    /* Distribute assignment to all contexts. */
404
0
    for (i = mb->literal_split.num_types; i != 0;) {
405
0
      size_t j = 0;
406
0
      i--;
407
0
      for (; j < (1 << BROTLI_LITERAL_CONTEXT_BITS); j++) {
408
0
        mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
409
0
            mb->literal_context_map[i];
410
0
      }
411
0
    }
412
0
  }
413
414
0
  if (num_base64_regions > 0 && mb->literal_split.num_types < 256 &&
415
0
      mb->literal_histograms_size < 256) {
416
0
    Base64Region local_b64[256];
417
0
    size_t safe_num_b64 = BROTLI_MIN(size_t, num_base64_regions, 256);
418
0
    MapBase64RegionsToLiteralPositions(cmds, num_commands, pos,
419
0
                                       base64_regions, safe_num_b64,
420
0
                                       local_b64);
421
0
    ForceBase64LiteralSplits(m, &mb->literal_split, local_b64,
422
0
                             safe_num_b64, 0, mb);
423
0
    if (!BROTLI_IS_OOM(m)) {
424
0
      AppendBase64Histogram(m, mb);
425
0
    }
426
0
    if (BROTLI_IS_OOM(m)) return;
427
0
  }
428
429
0
  BROTLI_DCHECK(mb->distance_context_map == 0);
430
0
  mb->distance_context_map_size =
431
0
      mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
432
0
  mb->distance_context_map =
433
0
      BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
434
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_context_map)) return;
435
436
0
  BROTLI_DCHECK(mb->distance_histograms == 0);
437
0
  mb->distance_histograms_size = mb->distance_context_map_size;
438
0
  mb->distance_histograms =
439
0
      BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
440
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_histograms)) return;
441
442
0
  BrotliClusterHistogramsDistance(m, distance_histograms,
443
0
                                  mb->distance_context_map_size,
444
0
                                  kMaxNumberOfHistograms,
445
0
                                  mb->distance_histograms,
446
0
                                  &mb->distance_histograms_size,
447
0
                                  mb->distance_context_map);
448
0
  if (BROTLI_IS_OOM(m)) return;
449
0
  BROTLI_FREE(m, distance_histograms);
450
0
}
451
452
0
#define FN(X) X ## Literal
453
#include "metablock_inc.h"  /* NOLINT(build/include) */
454
#undef FN
455
456
0
#define FN(X) X ## Command
457
#include "metablock_inc.h"  /* NOLINT(build/include) */
458
#undef FN
459
460
0
#define FN(X) X ## Distance
461
#include "metablock_inc.h"  /* NOLINT(build/include) */
462
#undef FN
463
464
/* Greedy block splitter for one block category (literal, command or distance).
465
   Gathers histograms for all context buckets. */
466
typedef struct ContextBlockSplitter {
467
  /* Alphabet size of particular block category. */
468
  size_t alphabet_size_;
469
  size_t num_contexts_;
470
  size_t max_block_types_;
471
  /* We collect at least this many symbols for each block. */
472
  size_t min_block_size_;
473
  /* We merge histograms A and B if
474
       entropy(A+B) < entropy(A) + entropy(B) + split_threshold_,
475
     where A is the current histogram and B is the histogram of the last or the
476
     second last block type. */
477
  double split_threshold_;
478
479
  size_t num_blocks_;
480
  BlockSplit* split_;  /* not owned */
481
  HistogramLiteral* histograms_;  /* not owned */
482
  size_t* histograms_size_;  /* not owned */
483
484
  /* The number of symbols that we want to collect before deciding on whether
485
     or not to merge the block with a previous one or emit a new block. */
486
  size_t target_block_size_;
487
  /* The number of symbols in the current histogram. */
488
  size_t block_size_;
489
  /* Offset of the current histogram. */
490
  size_t curr_histogram_ix_;
491
  /* Offset of the histograms of the previous two block types. */
492
  size_t last_histogram_ix_[2];
493
  /* Entropy of the previous two block types. */
494
  double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS];
495
  /* The number of times we merged the current block with the last one. */
496
  size_t merge_last_count_;
497
} ContextBlockSplitter;
498
499
static void InitContextBlockSplitter(
500
    MemoryManager* m, ContextBlockSplitter* self, size_t alphabet_size,
501
    size_t num_contexts, size_t min_block_size, double split_threshold,
502
    size_t num_symbols, BlockSplit* split, HistogramLiteral** histograms,
503
    size_t* histograms_size) {
504
  size_t max_num_blocks = num_symbols / min_block_size + 1;
505
  size_t max_num_types;
506
  BROTLI_DCHECK(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
507
508
  self->alphabet_size_ = alphabet_size;
509
  self->num_contexts_ = num_contexts;
510
  self->max_block_types_ = BROTLI_MAX_NUMBER_OF_BLOCK_TYPES / num_contexts;
511
  self->min_block_size_ = min_block_size;
512
  self->split_threshold_ = split_threshold;
513
  self->num_blocks_ = 0;
514
  self->split_ = split;
515
  self->histograms_size_ = histograms_size;
516
  self->target_block_size_ = min_block_size;
517
  self->block_size_ = 0;
518
  self->curr_histogram_ix_ = 0;
519
  self->merge_last_count_ = 0;
520
521
  /* We have to allocate one more histogram than the maximum number of block
522
     types for the current histogram when the meta-block is too big. */
523
  max_num_types =
524
      BROTLI_MIN(size_t, max_num_blocks, self->max_block_types_ + 1);
525
  BROTLI_ENSURE_CAPACITY(m, uint8_t,
526
      split->types, split->types_alloc_size, max_num_blocks);
527
  BROTLI_ENSURE_CAPACITY(m, uint32_t,
528
      split->lengths, split->lengths_alloc_size, max_num_blocks);
529
  if (BROTLI_IS_OOM(m)) return;
530
  split->num_blocks = max_num_blocks;
531
  if (BROTLI_IS_OOM(m)) return;
532
  BROTLI_DCHECK(*histograms == 0);
533
  *histograms_size = max_num_types * num_contexts;
534
  *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
535
  self->histograms_ = *histograms;
536
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
537
  /* Clear only current histogram. */
538
  ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
539
  self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
540
}
541
542
/* Does either of three things:
543
     (1) emits the current block with a new block type;
544
     (2) emits the current block with the type of the second last block;
545
     (3) merges the current block with the last block. */
546
static void ContextBlockSplitterFinishBlock(
547
0
    ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOL is_final) {
548
0
  BlockSplit* split = self->split_;
549
0
  const size_t num_contexts = self->num_contexts_;
550
0
  double* last_entropy = self->last_entropy_;
551
0
  HistogramLiteral* histograms = self->histograms_;
552
553
0
  if (self->block_size_ < self->min_block_size_) {
554
0
    self->block_size_ = self->min_block_size_;
555
0
  }
556
0
  if (self->num_blocks_ == 0) {
557
0
    size_t i;
558
    /* Create first block. */
559
0
    split->lengths[0] = (uint32_t)self->block_size_;
560
0
    split->types[0] = 0;
561
562
0
    for (i = 0; i < num_contexts; ++i) {
563
0
      last_entropy[i] =
564
0
          BrotliBitsEntropy(histograms[i].data_, self->alphabet_size_);
565
0
      last_entropy[num_contexts + i] = last_entropy[i];
566
0
    }
567
0
    ++self->num_blocks_;
568
0
    ++split->num_types;
569
0
    self->curr_histogram_ix_ += num_contexts;
570
0
    if (self->curr_histogram_ix_ < *self->histograms_size_) {
571
0
      ClearHistogramsLiteral(
572
0
          &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
573
0
    }
574
0
    self->block_size_ = 0;
575
0
  } else if (self->block_size_ > 0) {
576
    /* Try merging the set of histograms for the current block type with the
577
       respective set of histograms for the last and second last block types.
578
       Decide over the split based on the total reduction of entropy across
579
       all contexts. */
580
0
    double entropy[BROTLI_MAX_STATIC_CONTEXTS];
581
0
    HistogramLiteral* combined_histo =
582
0
        BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts);
583
0
    double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
584
0
    double diff[2] = { 0.0 };
585
0
    size_t i;
586
0
    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return;
587
0
    for (i = 0; i < num_contexts; ++i) {
588
0
      size_t curr_histo_ix = self->curr_histogram_ix_ + i;
589
0
      size_t j;
590
0
      entropy[i] = BrotliBitsEntropy(histograms[curr_histo_ix].data_,
591
0
                                     self->alphabet_size_);
592
0
      for (j = 0; j < 2; ++j) {
593
0
        size_t jx = j * num_contexts + i;
594
0
        size_t last_histogram_ix = self->last_histogram_ix_[j] + i;
595
0
        combined_histo[jx] = histograms[curr_histo_ix];
596
0
        HistogramAddHistogramLiteral(&combined_histo[jx],
597
0
            &histograms[last_histogram_ix]);
598
0
        combined_entropy[jx] = BrotliBitsEntropy(
599
0
            &combined_histo[jx].data_[0], self->alphabet_size_);
600
0
        diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx];
601
0
      }
602
0
    }
603
604
0
    if (split->num_types < self->max_block_types_ &&
605
0
        diff[0] > self->split_threshold_ &&
606
0
        diff[1] > self->split_threshold_) {
607
      /* Create new block. */
608
0
      split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
609
0
      split->types[self->num_blocks_] = (uint8_t)split->num_types;
610
0
      self->last_histogram_ix_[1] = self->last_histogram_ix_[0];
611
0
      self->last_histogram_ix_[0] = split->num_types * num_contexts;
612
0
      for (i = 0; i < num_contexts; ++i) {
613
0
        last_entropy[num_contexts + i] = last_entropy[i];
614
0
        last_entropy[i] = entropy[i];
615
0
      }
616
0
      ++self->num_blocks_;
617
0
      ++split->num_types;
618
0
      self->curr_histogram_ix_ += num_contexts;
619
0
      if (self->curr_histogram_ix_ < *self->histograms_size_) {
620
0
        ClearHistogramsLiteral(
621
0
            &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
622
0
      }
623
0
      self->block_size_ = 0;
624
0
      self->merge_last_count_ = 0;
625
0
      self->target_block_size_ = self->min_block_size_;
626
0
    } else if (diff[1] < diff[0] - 20.0) {
627
      /* Combine this block with second last block. */
628
0
      split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
629
0
      split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2];
630
0
      BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1);
631
0
      for (i = 0; i < num_contexts; ++i) {
632
0
        histograms[self->last_histogram_ix_[0] + i] =
633
0
            combined_histo[num_contexts + i];
634
0
        last_entropy[num_contexts + i] = last_entropy[i];
635
0
        last_entropy[i] = combined_entropy[num_contexts + i];
636
0
        HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
637
0
      }
638
0
      ++self->num_blocks_;
639
0
      self->block_size_ = 0;
640
0
      self->merge_last_count_ = 0;
641
0
      self->target_block_size_ = self->min_block_size_;
642
0
    } else {
643
      /* Combine this block with last block. */
644
0
      split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_;
645
0
      for (i = 0; i < num_contexts; ++i) {
646
0
        histograms[self->last_histogram_ix_[0] + i] = combined_histo[i];
647
0
        last_entropy[i] = combined_entropy[i];
648
0
        if (split->num_types == 1) {
649
0
          last_entropy[num_contexts + i] = last_entropy[i];
650
0
        }
651
0
        HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
652
0
      }
653
0
      self->block_size_ = 0;
654
0
      if (++self->merge_last_count_ > 1) {
655
0
        self->target_block_size_ += self->min_block_size_;
656
0
      }
657
0
    }
658
0
    BROTLI_FREE(m, combined_histo);
659
0
  }
660
0
  if (is_final) {
661
0
    *self->histograms_size_ = split->num_types * num_contexts;
662
0
    split->num_blocks = self->num_blocks_;
663
0
  }
664
0
}
665
666
/* Adds the next symbol to the current block type and context. When the
667
   current block reaches the target size, decides on merging the block. */
668
static void ContextBlockSplitterAddSymbol(
669
    ContextBlockSplitter* self, MemoryManager* m,
670
0
    size_t symbol, size_t context) {
671
0
  HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context],
672
0
      symbol);
673
0
  ++self->block_size_;
674
0
  if (self->block_size_ == self->target_block_size_) {
675
0
    ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE);
676
0
    if (BROTLI_IS_OOM(m)) return;
677
0
  }
678
0
}
679
680
static void MapStaticContexts(MemoryManager* m,
681
                              size_t num_contexts,
682
                              const uint32_t* static_context_map,
683
0
                              MetaBlockSplit* mb) {
684
0
  size_t i;
685
0
  BROTLI_DCHECK(mb->literal_context_map == 0);
686
0
  mb->literal_context_map_size =
687
0
      mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
688
0
  mb->literal_context_map =
689
0
      BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
690
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
691
692
0
  for (i = 0; i < mb->literal_split.num_types; ++i) {
693
0
    uint32_t offset = (uint32_t)(i * num_contexts);
694
0
    size_t j;
695
0
    for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS); ++j) {
696
0
      mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
697
0
          offset + static_context_map[j];
698
0
    }
699
0
  }
700
0
}
701
702
typedef struct GreedyMetablockArena {
703
  union {
704
    BlockSplitterLiteral plain;
705
    ContextBlockSplitter ctx;
706
  } lit_blocks;
707
  BlockSplitterCommand cmd_blocks;
708
  BlockSplitterDistance dist_blocks;
709
} GreedyMetablockArena;
710
711
static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
712
    MemoryManager* m, GreedyMetablockArena* arena, const uint8_t* ringbuffer,
713
    size_t pos, size_t mask, const Base64Region* base64_regions,
714
    size_t num_base64_regions, uint8_t prev_byte, uint8_t prev_byte2,
715
    ContextLut literal_context_lut, const size_t num_contexts,
716
    const uint32_t* static_context_map, const Command* commands,
717
0
    size_t n_commands, MetaBlockSplit* mb) {
718
0
  const size_t start_pos = pos;
719
0
  size_t num_literals = 0;
720
0
  size_t i;
721
0
  for (i = 0; i < n_commands; ++i) {
722
0
    num_literals += commands[i].insert_len_;
723
0
  }
724
725
0
  if (num_contexts == 1) {
726
0
    InitBlockSplitterLiteral(m, &arena->lit_blocks.plain, 256, 512, 400.0,
727
0
        num_literals, &mb->literal_split, &mb->literal_histograms,
728
0
        &mb->literal_histograms_size);
729
0
  } else {
730
0
    InitContextBlockSplitter(m, &arena->lit_blocks.ctx, 256, num_contexts, 512,
731
0
        400.0, num_literals, &mb->literal_split, &mb->literal_histograms,
732
0
        &mb->literal_histograms_size);
733
0
  }
734
0
  if (BROTLI_IS_OOM(m)) return;
735
0
  InitBlockSplitterCommand(m, &arena->cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS,
736
0
      1024, 500.0, n_commands, &mb->command_split, &mb->command_histograms,
737
0
      &mb->command_histograms_size);
738
0
  if (BROTLI_IS_OOM(m)) return;
739
0
  InitBlockSplitterDistance(m, &arena->dist_blocks, 64, 512, 100.0, n_commands,
740
0
      &mb->distance_split, &mb->distance_histograms,
741
0
      &mb->distance_histograms_size);
742
0
  if (BROTLI_IS_OOM(m)) return;
743
744
0
  for (i = 0; i < n_commands; ++i) {
745
0
    const Command cmd = commands[i];
746
0
    size_t j;
747
0
    BlockSplitterAddSymbolCommand(&arena->cmd_blocks, cmd.cmd_prefix_);
748
0
    for (j = cmd.insert_len_; j != 0; --j) {
749
0
      uint8_t literal = ringbuffer[pos & mask];
750
0
      if (num_contexts == 1) {
751
0
        BlockSplitterAddSymbolLiteral(&arena->lit_blocks.plain, literal);
752
0
      } else {
753
0
        size_t context =
754
0
            BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
755
0
        ContextBlockSplitterAddSymbol(&arena->lit_blocks.ctx, m, literal,
756
0
                                      static_context_map[context]);
757
0
        if (BROTLI_IS_OOM(m)) return;
758
0
      }
759
0
      prev_byte2 = prev_byte;
760
0
      prev_byte = literal;
761
0
      ++pos;
762
0
    }
763
0
    pos += CommandCopyLen(&cmd);
764
0
    if (CommandCopyLen(&cmd)) {
765
0
      prev_byte2 = ringbuffer[(pos - 2) & mask];
766
0
      prev_byte = ringbuffer[(pos - 1) & mask];
767
0
      if (cmd.cmd_prefix_ >= 128) {
768
0
        BlockSplitterAddSymbolDistance(
769
0
            &arena->dist_blocks, cmd.dist_prefix_ & 0x3FF);
770
0
      }
771
0
    }
772
0
  }
773
774
0
  if (num_contexts == 1) {
775
0
    BlockSplitterFinishBlockLiteral(
776
0
        &arena->lit_blocks.plain, /* is_final = */ BROTLI_TRUE);
777
0
  } else {
778
0
    ContextBlockSplitterFinishBlock(
779
0
        &arena->lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE);
780
0
    if (BROTLI_IS_OOM(m)) return;
781
0
  }
782
783
0
  if (num_base64_regions > 0 && mb->literal_split.num_types < 256 &&
784
0
      mb->literal_histograms_size + num_contexts <= 256) {
785
0
    Base64Region local_b64[256];
786
0
    size_t safe_num_b64 = BROTLI_MIN(size_t, num_base64_regions, 256);
787
0
    MapBase64RegionsToLiteralPositions(commands, n_commands, start_pos,
788
0
                                       base64_regions, safe_num_b64,
789
0
                                       local_b64);
790
0
    ForceBase64LiteralSplits(m, &mb->literal_split, local_b64,
791
0
                             safe_num_b64, 0, mb);
792
0
    if (BROTLI_IS_OOM(m)) return;
793
0
    {
794
0
      size_t num_b64_histos = num_contexts;
795
0
      size_t b64_histo_id = mb->literal_histograms_size;
796
0
      HistogramLiteral* new_histos = BROTLI_ALLOC(
797
0
          m, HistogramLiteral, mb->literal_histograms_size + num_b64_histos);
798
0
      if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_histos)) {
799
0
        return;
800
0
      }
801
0
      memcpy(new_histos, mb->literal_histograms,
802
0
             mb->literal_histograms_size * sizeof(HistogramLiteral));
803
0
      BROTLI_FREE(m, mb->literal_histograms);
804
0
      mb->literal_histograms = new_histos;
805
0
      for (i = 0; i < num_b64_histos; ++i) {
806
0
        HistogramClearLiteral(&mb->literal_histograms[b64_histo_id + i]);
807
0
      }
808
0
      mb->literal_histograms_size += num_b64_histos;
809
0
    }
810
0
  }
811
812
0
  BlockSplitterFinishBlockCommand(
813
0
      &arena->cmd_blocks, /* is_final = */ BROTLI_TRUE);
814
0
  BlockSplitterFinishBlockDistance(
815
0
      &arena->dist_blocks, /* is_final = */ BROTLI_TRUE);
816
817
0
  if (num_contexts > 1) {
818
0
    MapStaticContexts(m, num_contexts, static_context_map, mb);
819
0
  }
820
0
}
821
822
void BrotliBuildMetaBlockGreedy(
823
    MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
824
    const Base64Region* base64_regions, size_t num_base64_regions,
825
    uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut,
826
    size_t num_contexts, const uint32_t* static_context_map,
827
0
    const Command* commands, size_t n_commands, MetaBlockSplit* mb) {
828
0
  GreedyMetablockArena* arena = BROTLI_ALLOC(m, GreedyMetablockArena, 1);
829
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return;
830
0
  if (num_contexts == 1) {
831
0
    BrotliBuildMetaBlockGreedyInternal(
832
0
        m, arena, ringbuffer, pos, mask, base64_regions, num_base64_regions,
833
0
        prev_byte, prev_byte2, literal_context_lut, 1, NULL, commands,
834
0
        n_commands, mb);
835
0
  } else {
836
0
    BrotliBuildMetaBlockGreedyInternal(
837
0
        m, arena, ringbuffer, pos, mask, base64_regions, num_base64_regions,
838
0
        prev_byte, prev_byte2, literal_context_lut, num_contexts,
839
0
        static_context_map, commands, n_commands, mb);
840
0
  }
841
0
  BROTLI_FREE(m, arena);
842
0
}
843
844
void BrotliOptimizeHistograms(uint32_t num_distance_codes,
845
0
                              MetaBlockSplit* mb) {
846
0
  uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS];
847
0
  size_t i;
848
0
  for (i = 0; i < mb->literal_histograms_size; ++i) {
849
0
    BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_,
850
0
                                      good_for_rle);
851
0
  }
852
0
  for (i = 0; i < mb->command_histograms_size; ++i) {
853
0
    BrotliOptimizeHuffmanCountsForRle(BROTLI_NUM_COMMAND_SYMBOLS,
854
0
                                      mb->command_histograms[i].data_,
855
0
                                      good_for_rle);
856
0
  }
857
0
  for (i = 0; i < mb->distance_histograms_size; ++i) {
858
0
    BrotliOptimizeHuffmanCountsForRle(num_distance_codes,
859
0
                                      mb->distance_histograms[i].data_,
860
0
                                      good_for_rle);
861
0
  }
862
0
}
863
864
#if defined(__cplusplus) || defined(c_plusplus)
865
}  /* extern "C" */
866
#endif