Coverage Report

Created: 2025-07-23 06:37

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