xref: /third_party/node/deps/brotli/c/enc/metablock.c (revision 1cb0ef41)
11cb0ef41Sopenharmony_ci/* Copyright 2015 Google Inc. All Rights Reserved.
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci   Distributed under MIT license.
41cb0ef41Sopenharmony_ci   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
51cb0ef41Sopenharmony_ci*/
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci/* Algorithms for distributing the literals and commands of a metablock between
81cb0ef41Sopenharmony_ci   block types and contexts. */
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci#include "./metablock.h"
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci#include "../common/constants.h"
131cb0ef41Sopenharmony_ci#include "../common/context.h"
141cb0ef41Sopenharmony_ci#include "../common/platform.h"
151cb0ef41Sopenharmony_ci#include <brotli/types.h>
161cb0ef41Sopenharmony_ci#include "./bit_cost.h"
171cb0ef41Sopenharmony_ci#include "./block_splitter.h"
181cb0ef41Sopenharmony_ci#include "./cluster.h"
191cb0ef41Sopenharmony_ci#include "./entropy_encode.h"
201cb0ef41Sopenharmony_ci#include "./histogram.h"
211cb0ef41Sopenharmony_ci#include "./memory.h"
221cb0ef41Sopenharmony_ci#include "./quality.h"
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci#if defined(__cplusplus) || defined(c_plusplus)
251cb0ef41Sopenharmony_ciextern "C" {
261cb0ef41Sopenharmony_ci#endif
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_civoid BrotliInitDistanceParams(BrotliEncoderParams* params,
291cb0ef41Sopenharmony_ci    uint32_t npostfix, uint32_t ndirect) {
301cb0ef41Sopenharmony_ci  BrotliDistanceParams* dist_params = &params->dist;
311cb0ef41Sopenharmony_ci  uint32_t alphabet_size_max;
321cb0ef41Sopenharmony_ci  uint32_t alphabet_size_limit;
331cb0ef41Sopenharmony_ci  uint32_t max_distance;
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  dist_params->distance_postfix_bits = npostfix;
361cb0ef41Sopenharmony_ci  dist_params->num_direct_distance_codes = ndirect;
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
391cb0ef41Sopenharmony_ci      npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
401cb0ef41Sopenharmony_ci  alphabet_size_limit = alphabet_size_max;
411cb0ef41Sopenharmony_ci  max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) -
421cb0ef41Sopenharmony_ci      (1U << (npostfix + 2));
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  if (params->large_window) {
451cb0ef41Sopenharmony_ci    BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
461cb0ef41Sopenharmony_ci        BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
471cb0ef41Sopenharmony_ci    alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
481cb0ef41Sopenharmony_ci        npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
491cb0ef41Sopenharmony_ci    alphabet_size_limit = limit.max_alphabet_size;
501cb0ef41Sopenharmony_ci    max_distance = limit.max_distance;
511cb0ef41Sopenharmony_ci  }
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci  dist_params->alphabet_size_max = alphabet_size_max;
541cb0ef41Sopenharmony_ci  dist_params->alphabet_size_limit = alphabet_size_limit;
551cb0ef41Sopenharmony_ci  dist_params->max_distance = max_distance;
561cb0ef41Sopenharmony_ci}
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_cistatic void RecomputeDistancePrefixes(Command* cmds,
591cb0ef41Sopenharmony_ci                                      size_t num_commands,
601cb0ef41Sopenharmony_ci                                      const BrotliDistanceParams* orig_params,
611cb0ef41Sopenharmony_ci                                      const BrotliDistanceParams* new_params) {
621cb0ef41Sopenharmony_ci  size_t i;
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci  if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
651cb0ef41Sopenharmony_ci      orig_params->num_direct_distance_codes ==
661cb0ef41Sopenharmony_ci      new_params->num_direct_distance_codes) {
671cb0ef41Sopenharmony_ci    return;
681cb0ef41Sopenharmony_ci  }
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci  for (i = 0; i < num_commands; ++i) {
711cb0ef41Sopenharmony_ci    Command* cmd = &cmds[i];
721cb0ef41Sopenharmony_ci    if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
731cb0ef41Sopenharmony_ci      PrefixEncodeCopyDistance(CommandRestoreDistanceCode(cmd, orig_params),
741cb0ef41Sopenharmony_ci                               new_params->num_direct_distance_codes,
751cb0ef41Sopenharmony_ci                               new_params->distance_postfix_bits,
761cb0ef41Sopenharmony_ci                               &cmd->dist_prefix_,
771cb0ef41Sopenharmony_ci                               &cmd->dist_extra_);
781cb0ef41Sopenharmony_ci    }
791cb0ef41Sopenharmony_ci  }
801cb0ef41Sopenharmony_ci}
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_cistatic BROTLI_BOOL ComputeDistanceCost(const Command* cmds,
831cb0ef41Sopenharmony_ci                                       size_t num_commands,
841cb0ef41Sopenharmony_ci                                       const BrotliDistanceParams* orig_params,
851cb0ef41Sopenharmony_ci                                       const BrotliDistanceParams* new_params,
861cb0ef41Sopenharmony_ci                                       double* cost) {
871cb0ef41Sopenharmony_ci  size_t i;
881cb0ef41Sopenharmony_ci  BROTLI_BOOL equal_params = BROTLI_FALSE;
891cb0ef41Sopenharmony_ci  uint16_t dist_prefix;
901cb0ef41Sopenharmony_ci  uint32_t dist_extra;
911cb0ef41Sopenharmony_ci  double extra_bits = 0.0;
921cb0ef41Sopenharmony_ci  HistogramDistance histo;
931cb0ef41Sopenharmony_ci  HistogramClearDistance(&histo);
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
961cb0ef41Sopenharmony_ci      orig_params->num_direct_distance_codes ==
971cb0ef41Sopenharmony_ci      new_params->num_direct_distance_codes) {
981cb0ef41Sopenharmony_ci    equal_params = BROTLI_TRUE;
991cb0ef41Sopenharmony_ci  }
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci  for (i = 0; i < num_commands; i++) {
1021cb0ef41Sopenharmony_ci    const Command* cmd = &cmds[i];
1031cb0ef41Sopenharmony_ci    if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
1041cb0ef41Sopenharmony_ci      if (equal_params) {
1051cb0ef41Sopenharmony_ci        dist_prefix = cmd->dist_prefix_;
1061cb0ef41Sopenharmony_ci      } else {
1071cb0ef41Sopenharmony_ci        uint32_t distance = CommandRestoreDistanceCode(cmd, orig_params);
1081cb0ef41Sopenharmony_ci        if (distance > new_params->max_distance) {
1091cb0ef41Sopenharmony_ci          return BROTLI_FALSE;
1101cb0ef41Sopenharmony_ci        }
1111cb0ef41Sopenharmony_ci        PrefixEncodeCopyDistance(distance,
1121cb0ef41Sopenharmony_ci                                 new_params->num_direct_distance_codes,
1131cb0ef41Sopenharmony_ci                                 new_params->distance_postfix_bits,
1141cb0ef41Sopenharmony_ci                                 &dist_prefix,
1151cb0ef41Sopenharmony_ci                                 &dist_extra);
1161cb0ef41Sopenharmony_ci      }
1171cb0ef41Sopenharmony_ci      HistogramAddDistance(&histo, dist_prefix & 0x3FF);
1181cb0ef41Sopenharmony_ci      extra_bits += dist_prefix >> 10;
1191cb0ef41Sopenharmony_ci    }
1201cb0ef41Sopenharmony_ci  }
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  *cost = BrotliPopulationCostDistance(&histo) + extra_bits;
1231cb0ef41Sopenharmony_ci  return BROTLI_TRUE;
1241cb0ef41Sopenharmony_ci}
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_civoid BrotliBuildMetaBlock(MemoryManager* m,
1271cb0ef41Sopenharmony_ci                          const uint8_t* ringbuffer,
1281cb0ef41Sopenharmony_ci                          const size_t pos,
1291cb0ef41Sopenharmony_ci                          const size_t mask,
1301cb0ef41Sopenharmony_ci                          BrotliEncoderParams* params,
1311cb0ef41Sopenharmony_ci                          uint8_t prev_byte,
1321cb0ef41Sopenharmony_ci                          uint8_t prev_byte2,
1331cb0ef41Sopenharmony_ci                          Command* cmds,
1341cb0ef41Sopenharmony_ci                          size_t num_commands,
1351cb0ef41Sopenharmony_ci                          ContextType literal_context_mode,
1361cb0ef41Sopenharmony_ci                          MetaBlockSplit* mb) {
1371cb0ef41Sopenharmony_ci  /* Histogram ids need to fit in one byte. */
1381cb0ef41Sopenharmony_ci  static const size_t kMaxNumberOfHistograms = 256;
1391cb0ef41Sopenharmony_ci  HistogramDistance* distance_histograms;
1401cb0ef41Sopenharmony_ci  HistogramLiteral* literal_histograms;
1411cb0ef41Sopenharmony_ci  ContextType* literal_context_modes = NULL;
1421cb0ef41Sopenharmony_ci  size_t literal_histograms_size;
1431cb0ef41Sopenharmony_ci  size_t distance_histograms_size;
1441cb0ef41Sopenharmony_ci  size_t i;
1451cb0ef41Sopenharmony_ci  size_t literal_context_multiplier = 1;
1461cb0ef41Sopenharmony_ci  uint32_t npostfix;
1471cb0ef41Sopenharmony_ci  uint32_t ndirect_msb = 0;
1481cb0ef41Sopenharmony_ci  BROTLI_BOOL check_orig = BROTLI_TRUE;
1491cb0ef41Sopenharmony_ci  double best_dist_cost = 1e99;
1501cb0ef41Sopenharmony_ci  BrotliEncoderParams orig_params = *params;
1511cb0ef41Sopenharmony_ci  BrotliEncoderParams new_params = *params;
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  for (npostfix = 0; npostfix <= BROTLI_MAX_NPOSTFIX; npostfix++) {
1541cb0ef41Sopenharmony_ci    for (; ndirect_msb < 16; ndirect_msb++) {
1551cb0ef41Sopenharmony_ci      uint32_t ndirect = ndirect_msb << npostfix;
1561cb0ef41Sopenharmony_ci      BROTLI_BOOL skip;
1571cb0ef41Sopenharmony_ci      double dist_cost;
1581cb0ef41Sopenharmony_ci      BrotliInitDistanceParams(&new_params, npostfix, ndirect);
1591cb0ef41Sopenharmony_ci      if (npostfix == orig_params.dist.distance_postfix_bits &&
1601cb0ef41Sopenharmony_ci          ndirect == orig_params.dist.num_direct_distance_codes) {
1611cb0ef41Sopenharmony_ci        check_orig = BROTLI_FALSE;
1621cb0ef41Sopenharmony_ci      }
1631cb0ef41Sopenharmony_ci      skip = !ComputeDistanceCost(
1641cb0ef41Sopenharmony_ci          cmds, num_commands,
1651cb0ef41Sopenharmony_ci          &orig_params.dist, &new_params.dist, &dist_cost);
1661cb0ef41Sopenharmony_ci      if (skip || (dist_cost > best_dist_cost)) {
1671cb0ef41Sopenharmony_ci        break;
1681cb0ef41Sopenharmony_ci      }
1691cb0ef41Sopenharmony_ci      best_dist_cost = dist_cost;
1701cb0ef41Sopenharmony_ci      params->dist = new_params.dist;
1711cb0ef41Sopenharmony_ci    }
1721cb0ef41Sopenharmony_ci    if (ndirect_msb > 0) ndirect_msb--;
1731cb0ef41Sopenharmony_ci    ndirect_msb /= 2;
1741cb0ef41Sopenharmony_ci  }
1751cb0ef41Sopenharmony_ci  if (check_orig) {
1761cb0ef41Sopenharmony_ci    double dist_cost;
1771cb0ef41Sopenharmony_ci    ComputeDistanceCost(cmds, num_commands,
1781cb0ef41Sopenharmony_ci                        &orig_params.dist, &orig_params.dist, &dist_cost);
1791cb0ef41Sopenharmony_ci    if (dist_cost < best_dist_cost) {
1801cb0ef41Sopenharmony_ci      /* NB: currently unused; uncomment when more param tuning is added. */
1811cb0ef41Sopenharmony_ci      /* best_dist_cost = dist_cost; */
1821cb0ef41Sopenharmony_ci      params->dist = orig_params.dist;
1831cb0ef41Sopenharmony_ci    }
1841cb0ef41Sopenharmony_ci  }
1851cb0ef41Sopenharmony_ci  RecomputeDistancePrefixes(cmds, num_commands,
1861cb0ef41Sopenharmony_ci                            &orig_params.dist, &params->dist);
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci  BrotliSplitBlock(m, cmds, num_commands,
1891cb0ef41Sopenharmony_ci                   ringbuffer, pos, mask, params,
1901cb0ef41Sopenharmony_ci                   &mb->literal_split,
1911cb0ef41Sopenharmony_ci                   &mb->command_split,
1921cb0ef41Sopenharmony_ci                   &mb->distance_split);
1931cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m)) return;
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci  if (!params->disable_literal_context_modeling) {
1961cb0ef41Sopenharmony_ci    literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
1971cb0ef41Sopenharmony_ci    literal_context_modes =
1981cb0ef41Sopenharmony_ci        BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
1991cb0ef41Sopenharmony_ci    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_context_modes)) return;
2001cb0ef41Sopenharmony_ci    for (i = 0; i < mb->literal_split.num_types; ++i) {
2011cb0ef41Sopenharmony_ci      literal_context_modes[i] = literal_context_mode;
2021cb0ef41Sopenharmony_ci    }
2031cb0ef41Sopenharmony_ci  }
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_ci  literal_histograms_size =
2061cb0ef41Sopenharmony_ci      mb->literal_split.num_types * literal_context_multiplier;
2071cb0ef41Sopenharmony_ci  literal_histograms =
2081cb0ef41Sopenharmony_ci      BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
2091cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_histograms)) return;
2101cb0ef41Sopenharmony_ci  ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci  distance_histograms_size =
2131cb0ef41Sopenharmony_ci      mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
2141cb0ef41Sopenharmony_ci  distance_histograms =
2151cb0ef41Sopenharmony_ci      BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
2161cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_histograms)) return;
2171cb0ef41Sopenharmony_ci  ClearHistogramsDistance(distance_histograms, distance_histograms_size);
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci  BROTLI_DCHECK(mb->command_histograms == 0);
2201cb0ef41Sopenharmony_ci  mb->command_histograms_size = mb->command_split.num_types;
2211cb0ef41Sopenharmony_ci  mb->command_histograms =
2221cb0ef41Sopenharmony_ci      BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
2231cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->command_histograms)) return;
2241cb0ef41Sopenharmony_ci  ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci  BrotliBuildHistogramsWithContext(cmds, num_commands,
2271cb0ef41Sopenharmony_ci      &mb->literal_split, &mb->command_split, &mb->distance_split,
2281cb0ef41Sopenharmony_ci      ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes,
2291cb0ef41Sopenharmony_ci      literal_histograms, mb->command_histograms, distance_histograms);
2301cb0ef41Sopenharmony_ci  BROTLI_FREE(m, literal_context_modes);
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci  BROTLI_DCHECK(mb->literal_context_map == 0);
2331cb0ef41Sopenharmony_ci  mb->literal_context_map_size =
2341cb0ef41Sopenharmony_ci      mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
2351cb0ef41Sopenharmony_ci  mb->literal_context_map =
2361cb0ef41Sopenharmony_ci      BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
2371cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci  BROTLI_DCHECK(mb->literal_histograms == 0);
2401cb0ef41Sopenharmony_ci  mb->literal_histograms_size = mb->literal_context_map_size;
2411cb0ef41Sopenharmony_ci  mb->literal_histograms =
2421cb0ef41Sopenharmony_ci      BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
2431cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_histograms)) return;
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci  BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
2461cb0ef41Sopenharmony_ci      kMaxNumberOfHistograms, mb->literal_histograms,
2471cb0ef41Sopenharmony_ci      &mb->literal_histograms_size, mb->literal_context_map);
2481cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m)) return;
2491cb0ef41Sopenharmony_ci  BROTLI_FREE(m, literal_histograms);
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci  if (params->disable_literal_context_modeling) {
2521cb0ef41Sopenharmony_ci    /* Distribute assignment to all contexts. */
2531cb0ef41Sopenharmony_ci    for (i = mb->literal_split.num_types; i != 0;) {
2541cb0ef41Sopenharmony_ci      size_t j = 0;
2551cb0ef41Sopenharmony_ci      i--;
2561cb0ef41Sopenharmony_ci      for (; j < (1 << BROTLI_LITERAL_CONTEXT_BITS); j++) {
2571cb0ef41Sopenharmony_ci        mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
2581cb0ef41Sopenharmony_ci            mb->literal_context_map[i];
2591cb0ef41Sopenharmony_ci      }
2601cb0ef41Sopenharmony_ci    }
2611cb0ef41Sopenharmony_ci  }
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  BROTLI_DCHECK(mb->distance_context_map == 0);
2641cb0ef41Sopenharmony_ci  mb->distance_context_map_size =
2651cb0ef41Sopenharmony_ci      mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
2661cb0ef41Sopenharmony_ci  mb->distance_context_map =
2671cb0ef41Sopenharmony_ci      BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
2681cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_context_map)) return;
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci  BROTLI_DCHECK(mb->distance_histograms == 0);
2711cb0ef41Sopenharmony_ci  mb->distance_histograms_size = mb->distance_context_map_size;
2721cb0ef41Sopenharmony_ci  mb->distance_histograms =
2731cb0ef41Sopenharmony_ci      BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
2741cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_histograms)) return;
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_ci  BrotliClusterHistogramsDistance(m, distance_histograms,
2771cb0ef41Sopenharmony_ci                                  mb->distance_context_map_size,
2781cb0ef41Sopenharmony_ci                                  kMaxNumberOfHistograms,
2791cb0ef41Sopenharmony_ci                                  mb->distance_histograms,
2801cb0ef41Sopenharmony_ci                                  &mb->distance_histograms_size,
2811cb0ef41Sopenharmony_ci                                  mb->distance_context_map);
2821cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m)) return;
2831cb0ef41Sopenharmony_ci  BROTLI_FREE(m, distance_histograms);
2841cb0ef41Sopenharmony_ci}
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci#define FN(X) X ## Literal
2871cb0ef41Sopenharmony_ci#include "./metablock_inc.h"  /* NOLINT(build/include) */
2881cb0ef41Sopenharmony_ci#undef FN
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci#define FN(X) X ## Command
2911cb0ef41Sopenharmony_ci#include "./metablock_inc.h"  /* NOLINT(build/include) */
2921cb0ef41Sopenharmony_ci#undef FN
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci#define FN(X) X ## Distance
2951cb0ef41Sopenharmony_ci#include "./metablock_inc.h"  /* NOLINT(build/include) */
2961cb0ef41Sopenharmony_ci#undef FN
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci#define BROTLI_MAX_STATIC_CONTEXTS 13
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci/* Greedy block splitter for one block category (literal, command or distance).
3011cb0ef41Sopenharmony_ci   Gathers histograms for all context buckets. */
3021cb0ef41Sopenharmony_citypedef struct ContextBlockSplitter {
3031cb0ef41Sopenharmony_ci  /* Alphabet size of particular block category. */
3041cb0ef41Sopenharmony_ci  size_t alphabet_size_;
3051cb0ef41Sopenharmony_ci  size_t num_contexts_;
3061cb0ef41Sopenharmony_ci  size_t max_block_types_;
3071cb0ef41Sopenharmony_ci  /* We collect at least this many symbols for each block. */
3081cb0ef41Sopenharmony_ci  size_t min_block_size_;
3091cb0ef41Sopenharmony_ci  /* We merge histograms A and B if
3101cb0ef41Sopenharmony_ci       entropy(A+B) < entropy(A) + entropy(B) + split_threshold_,
3111cb0ef41Sopenharmony_ci     where A is the current histogram and B is the histogram of the last or the
3121cb0ef41Sopenharmony_ci     second last block type. */
3131cb0ef41Sopenharmony_ci  double split_threshold_;
3141cb0ef41Sopenharmony_ci
3151cb0ef41Sopenharmony_ci  size_t num_blocks_;
3161cb0ef41Sopenharmony_ci  BlockSplit* split_;  /* not owned */
3171cb0ef41Sopenharmony_ci  HistogramLiteral* histograms_;  /* not owned */
3181cb0ef41Sopenharmony_ci  size_t* histograms_size_;  /* not owned */
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ci  /* The number of symbols that we want to collect before deciding on whether
3211cb0ef41Sopenharmony_ci     or not to merge the block with a previous one or emit a new block. */
3221cb0ef41Sopenharmony_ci  size_t target_block_size_;
3231cb0ef41Sopenharmony_ci  /* The number of symbols in the current histogram. */
3241cb0ef41Sopenharmony_ci  size_t block_size_;
3251cb0ef41Sopenharmony_ci  /* Offset of the current histogram. */
3261cb0ef41Sopenharmony_ci  size_t curr_histogram_ix_;
3271cb0ef41Sopenharmony_ci  /* Offset of the histograms of the previous two block types. */
3281cb0ef41Sopenharmony_ci  size_t last_histogram_ix_[2];
3291cb0ef41Sopenharmony_ci  /* Entropy of the previous two block types. */
3301cb0ef41Sopenharmony_ci  double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS];
3311cb0ef41Sopenharmony_ci  /* The number of times we merged the current block with the last one. */
3321cb0ef41Sopenharmony_ci  size_t merge_last_count_;
3331cb0ef41Sopenharmony_ci} ContextBlockSplitter;
3341cb0ef41Sopenharmony_ci
3351cb0ef41Sopenharmony_cistatic void InitContextBlockSplitter(
3361cb0ef41Sopenharmony_ci    MemoryManager* m, ContextBlockSplitter* self, size_t alphabet_size,
3371cb0ef41Sopenharmony_ci    size_t num_contexts, size_t min_block_size, double split_threshold,
3381cb0ef41Sopenharmony_ci    size_t num_symbols, BlockSplit* split, HistogramLiteral** histograms,
3391cb0ef41Sopenharmony_ci    size_t* histograms_size) {
3401cb0ef41Sopenharmony_ci  size_t max_num_blocks = num_symbols / min_block_size + 1;
3411cb0ef41Sopenharmony_ci  size_t max_num_types;
3421cb0ef41Sopenharmony_ci  BROTLI_DCHECK(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci  self->alphabet_size_ = alphabet_size;
3451cb0ef41Sopenharmony_ci  self->num_contexts_ = num_contexts;
3461cb0ef41Sopenharmony_ci  self->max_block_types_ = BROTLI_MAX_NUMBER_OF_BLOCK_TYPES / num_contexts;
3471cb0ef41Sopenharmony_ci  self->min_block_size_ = min_block_size;
3481cb0ef41Sopenharmony_ci  self->split_threshold_ = split_threshold;
3491cb0ef41Sopenharmony_ci  self->num_blocks_ = 0;
3501cb0ef41Sopenharmony_ci  self->split_ = split;
3511cb0ef41Sopenharmony_ci  self->histograms_size_ = histograms_size;
3521cb0ef41Sopenharmony_ci  self->target_block_size_ = min_block_size;
3531cb0ef41Sopenharmony_ci  self->block_size_ = 0;
3541cb0ef41Sopenharmony_ci  self->curr_histogram_ix_ = 0;
3551cb0ef41Sopenharmony_ci  self->merge_last_count_ = 0;
3561cb0ef41Sopenharmony_ci
3571cb0ef41Sopenharmony_ci  /* We have to allocate one more histogram than the maximum number of block
3581cb0ef41Sopenharmony_ci     types for the current histogram when the meta-block is too big. */
3591cb0ef41Sopenharmony_ci  max_num_types =
3601cb0ef41Sopenharmony_ci      BROTLI_MIN(size_t, max_num_blocks, self->max_block_types_ + 1);
3611cb0ef41Sopenharmony_ci  BROTLI_ENSURE_CAPACITY(m, uint8_t,
3621cb0ef41Sopenharmony_ci      split->types, split->types_alloc_size, max_num_blocks);
3631cb0ef41Sopenharmony_ci  BROTLI_ENSURE_CAPACITY(m, uint32_t,
3641cb0ef41Sopenharmony_ci      split->lengths, split->lengths_alloc_size, max_num_blocks);
3651cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m)) return;
3661cb0ef41Sopenharmony_ci  split->num_blocks = max_num_blocks;
3671cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m)) return;
3681cb0ef41Sopenharmony_ci  BROTLI_DCHECK(*histograms == 0);
3691cb0ef41Sopenharmony_ci  *histograms_size = max_num_types * num_contexts;
3701cb0ef41Sopenharmony_ci  *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
3711cb0ef41Sopenharmony_ci  self->histograms_ = *histograms;
3721cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
3731cb0ef41Sopenharmony_ci  /* Clear only current histogram. */
3741cb0ef41Sopenharmony_ci  ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
3751cb0ef41Sopenharmony_ci  self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
3761cb0ef41Sopenharmony_ci}
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ci/* Does either of three things:
3791cb0ef41Sopenharmony_ci     (1) emits the current block with a new block type;
3801cb0ef41Sopenharmony_ci     (2) emits the current block with the type of the second last block;
3811cb0ef41Sopenharmony_ci     (3) merges the current block with the last block. */
3821cb0ef41Sopenharmony_cistatic void ContextBlockSplitterFinishBlock(
3831cb0ef41Sopenharmony_ci    ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOL is_final) {
3841cb0ef41Sopenharmony_ci  BlockSplit* split = self->split_;
3851cb0ef41Sopenharmony_ci  const size_t num_contexts = self->num_contexts_;
3861cb0ef41Sopenharmony_ci  double* last_entropy = self->last_entropy_;
3871cb0ef41Sopenharmony_ci  HistogramLiteral* histograms = self->histograms_;
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_ci  if (self->block_size_ < self->min_block_size_) {
3901cb0ef41Sopenharmony_ci    self->block_size_ = self->min_block_size_;
3911cb0ef41Sopenharmony_ci  }
3921cb0ef41Sopenharmony_ci  if (self->num_blocks_ == 0) {
3931cb0ef41Sopenharmony_ci    size_t i;
3941cb0ef41Sopenharmony_ci    /* Create first block. */
3951cb0ef41Sopenharmony_ci    split->lengths[0] = (uint32_t)self->block_size_;
3961cb0ef41Sopenharmony_ci    split->types[0] = 0;
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci    for (i = 0; i < num_contexts; ++i) {
3991cb0ef41Sopenharmony_ci      last_entropy[i] =
4001cb0ef41Sopenharmony_ci          BitsEntropy(histograms[i].data_, self->alphabet_size_);
4011cb0ef41Sopenharmony_ci      last_entropy[num_contexts + i] = last_entropy[i];
4021cb0ef41Sopenharmony_ci    }
4031cb0ef41Sopenharmony_ci    ++self->num_blocks_;
4041cb0ef41Sopenharmony_ci    ++split->num_types;
4051cb0ef41Sopenharmony_ci    self->curr_histogram_ix_ += num_contexts;
4061cb0ef41Sopenharmony_ci    if (self->curr_histogram_ix_ < *self->histograms_size_) {
4071cb0ef41Sopenharmony_ci      ClearHistogramsLiteral(
4081cb0ef41Sopenharmony_ci          &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
4091cb0ef41Sopenharmony_ci    }
4101cb0ef41Sopenharmony_ci    self->block_size_ = 0;
4111cb0ef41Sopenharmony_ci  } else if (self->block_size_ > 0) {
4121cb0ef41Sopenharmony_ci    /* Try merging the set of histograms for the current block type with the
4131cb0ef41Sopenharmony_ci       respective set of histograms for the last and second last block types.
4141cb0ef41Sopenharmony_ci       Decide over the split based on the total reduction of entropy across
4151cb0ef41Sopenharmony_ci       all contexts. */
4161cb0ef41Sopenharmony_ci    double entropy[BROTLI_MAX_STATIC_CONTEXTS];
4171cb0ef41Sopenharmony_ci    HistogramLiteral* combined_histo =
4181cb0ef41Sopenharmony_ci        BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts);
4191cb0ef41Sopenharmony_ci    double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
4201cb0ef41Sopenharmony_ci    double diff[2] = { 0.0 };
4211cb0ef41Sopenharmony_ci    size_t i;
4221cb0ef41Sopenharmony_ci    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return;
4231cb0ef41Sopenharmony_ci    for (i = 0; i < num_contexts; ++i) {
4241cb0ef41Sopenharmony_ci      size_t curr_histo_ix = self->curr_histogram_ix_ + i;
4251cb0ef41Sopenharmony_ci      size_t j;
4261cb0ef41Sopenharmony_ci      entropy[i] = BitsEntropy(histograms[curr_histo_ix].data_,
4271cb0ef41Sopenharmony_ci                               self->alphabet_size_);
4281cb0ef41Sopenharmony_ci      for (j = 0; j < 2; ++j) {
4291cb0ef41Sopenharmony_ci        size_t jx = j * num_contexts + i;
4301cb0ef41Sopenharmony_ci        size_t last_histogram_ix = self->last_histogram_ix_[j] + i;
4311cb0ef41Sopenharmony_ci        combined_histo[jx] = histograms[curr_histo_ix];
4321cb0ef41Sopenharmony_ci        HistogramAddHistogramLiteral(&combined_histo[jx],
4331cb0ef41Sopenharmony_ci            &histograms[last_histogram_ix]);
4341cb0ef41Sopenharmony_ci        combined_entropy[jx] = BitsEntropy(
4351cb0ef41Sopenharmony_ci            &combined_histo[jx].data_[0], self->alphabet_size_);
4361cb0ef41Sopenharmony_ci        diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx];
4371cb0ef41Sopenharmony_ci      }
4381cb0ef41Sopenharmony_ci    }
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci    if (split->num_types < self->max_block_types_ &&
4411cb0ef41Sopenharmony_ci        diff[0] > self->split_threshold_ &&
4421cb0ef41Sopenharmony_ci        diff[1] > self->split_threshold_) {
4431cb0ef41Sopenharmony_ci      /* Create new block. */
4441cb0ef41Sopenharmony_ci      split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
4451cb0ef41Sopenharmony_ci      split->types[self->num_blocks_] = (uint8_t)split->num_types;
4461cb0ef41Sopenharmony_ci      self->last_histogram_ix_[1] = self->last_histogram_ix_[0];
4471cb0ef41Sopenharmony_ci      self->last_histogram_ix_[0] = split->num_types * num_contexts;
4481cb0ef41Sopenharmony_ci      for (i = 0; i < num_contexts; ++i) {
4491cb0ef41Sopenharmony_ci        last_entropy[num_contexts + i] = last_entropy[i];
4501cb0ef41Sopenharmony_ci        last_entropy[i] = entropy[i];
4511cb0ef41Sopenharmony_ci      }
4521cb0ef41Sopenharmony_ci      ++self->num_blocks_;
4531cb0ef41Sopenharmony_ci      ++split->num_types;
4541cb0ef41Sopenharmony_ci      self->curr_histogram_ix_ += num_contexts;
4551cb0ef41Sopenharmony_ci      if (self->curr_histogram_ix_ < *self->histograms_size_) {
4561cb0ef41Sopenharmony_ci        ClearHistogramsLiteral(
4571cb0ef41Sopenharmony_ci            &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
4581cb0ef41Sopenharmony_ci      }
4591cb0ef41Sopenharmony_ci      self->block_size_ = 0;
4601cb0ef41Sopenharmony_ci      self->merge_last_count_ = 0;
4611cb0ef41Sopenharmony_ci      self->target_block_size_ = self->min_block_size_;
4621cb0ef41Sopenharmony_ci    } else if (diff[1] < diff[0] - 20.0) {
4631cb0ef41Sopenharmony_ci      /* Combine this block with second last block. */
4641cb0ef41Sopenharmony_ci      split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
4651cb0ef41Sopenharmony_ci      split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2];
4661cb0ef41Sopenharmony_ci      BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1);
4671cb0ef41Sopenharmony_ci      for (i = 0; i < num_contexts; ++i) {
4681cb0ef41Sopenharmony_ci        histograms[self->last_histogram_ix_[0] + i] =
4691cb0ef41Sopenharmony_ci            combined_histo[num_contexts + i];
4701cb0ef41Sopenharmony_ci        last_entropy[num_contexts + i] = last_entropy[i];
4711cb0ef41Sopenharmony_ci        last_entropy[i] = combined_entropy[num_contexts + i];
4721cb0ef41Sopenharmony_ci        HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
4731cb0ef41Sopenharmony_ci      }
4741cb0ef41Sopenharmony_ci      ++self->num_blocks_;
4751cb0ef41Sopenharmony_ci      self->block_size_ = 0;
4761cb0ef41Sopenharmony_ci      self->merge_last_count_ = 0;
4771cb0ef41Sopenharmony_ci      self->target_block_size_ = self->min_block_size_;
4781cb0ef41Sopenharmony_ci    } else {
4791cb0ef41Sopenharmony_ci      /* Combine this block with last block. */
4801cb0ef41Sopenharmony_ci      split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_;
4811cb0ef41Sopenharmony_ci      for (i = 0; i < num_contexts; ++i) {
4821cb0ef41Sopenharmony_ci        histograms[self->last_histogram_ix_[0] + i] = combined_histo[i];
4831cb0ef41Sopenharmony_ci        last_entropy[i] = combined_entropy[i];
4841cb0ef41Sopenharmony_ci        if (split->num_types == 1) {
4851cb0ef41Sopenharmony_ci          last_entropy[num_contexts + i] = last_entropy[i];
4861cb0ef41Sopenharmony_ci        }
4871cb0ef41Sopenharmony_ci        HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
4881cb0ef41Sopenharmony_ci      }
4891cb0ef41Sopenharmony_ci      self->block_size_ = 0;
4901cb0ef41Sopenharmony_ci      if (++self->merge_last_count_ > 1) {
4911cb0ef41Sopenharmony_ci        self->target_block_size_ += self->min_block_size_;
4921cb0ef41Sopenharmony_ci      }
4931cb0ef41Sopenharmony_ci    }
4941cb0ef41Sopenharmony_ci    BROTLI_FREE(m, combined_histo);
4951cb0ef41Sopenharmony_ci  }
4961cb0ef41Sopenharmony_ci  if (is_final) {
4971cb0ef41Sopenharmony_ci    *self->histograms_size_ = split->num_types * num_contexts;
4981cb0ef41Sopenharmony_ci    split->num_blocks = self->num_blocks_;
4991cb0ef41Sopenharmony_ci  }
5001cb0ef41Sopenharmony_ci}
5011cb0ef41Sopenharmony_ci
5021cb0ef41Sopenharmony_ci/* Adds the next symbol to the current block type and context. When the
5031cb0ef41Sopenharmony_ci   current block reaches the target size, decides on merging the block. */
5041cb0ef41Sopenharmony_cistatic void ContextBlockSplitterAddSymbol(
5051cb0ef41Sopenharmony_ci    ContextBlockSplitter* self, MemoryManager* m,
5061cb0ef41Sopenharmony_ci    size_t symbol, size_t context) {
5071cb0ef41Sopenharmony_ci  HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context],
5081cb0ef41Sopenharmony_ci      symbol);
5091cb0ef41Sopenharmony_ci  ++self->block_size_;
5101cb0ef41Sopenharmony_ci  if (self->block_size_ == self->target_block_size_) {
5111cb0ef41Sopenharmony_ci    ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE);
5121cb0ef41Sopenharmony_ci    if (BROTLI_IS_OOM(m)) return;
5131cb0ef41Sopenharmony_ci  }
5141cb0ef41Sopenharmony_ci}
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_cistatic void MapStaticContexts(MemoryManager* m,
5171cb0ef41Sopenharmony_ci                              size_t num_contexts,
5181cb0ef41Sopenharmony_ci                              const uint32_t* static_context_map,
5191cb0ef41Sopenharmony_ci                              MetaBlockSplit* mb) {
5201cb0ef41Sopenharmony_ci  size_t i;
5211cb0ef41Sopenharmony_ci  BROTLI_DCHECK(mb->literal_context_map == 0);
5221cb0ef41Sopenharmony_ci  mb->literal_context_map_size =
5231cb0ef41Sopenharmony_ci      mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
5241cb0ef41Sopenharmony_ci  mb->literal_context_map =
5251cb0ef41Sopenharmony_ci      BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
5261cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
5271cb0ef41Sopenharmony_ci
5281cb0ef41Sopenharmony_ci  for (i = 0; i < mb->literal_split.num_types; ++i) {
5291cb0ef41Sopenharmony_ci    uint32_t offset = (uint32_t)(i * num_contexts);
5301cb0ef41Sopenharmony_ci    size_t j;
5311cb0ef41Sopenharmony_ci    for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS); ++j) {
5321cb0ef41Sopenharmony_ci      mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
5331cb0ef41Sopenharmony_ci          offset + static_context_map[j];
5341cb0ef41Sopenharmony_ci    }
5351cb0ef41Sopenharmony_ci  }
5361cb0ef41Sopenharmony_ci}
5371cb0ef41Sopenharmony_ci
5381cb0ef41Sopenharmony_cistatic BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
5391cb0ef41Sopenharmony_ci    MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
5401cb0ef41Sopenharmony_ci    uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut,
5411cb0ef41Sopenharmony_ci    const size_t num_contexts, const uint32_t* static_context_map,
5421cb0ef41Sopenharmony_ci    const Command* commands, size_t n_commands, MetaBlockSplit* mb) {
5431cb0ef41Sopenharmony_ci  union {
5441cb0ef41Sopenharmony_ci    BlockSplitterLiteral plain;
5451cb0ef41Sopenharmony_ci    ContextBlockSplitter ctx;
5461cb0ef41Sopenharmony_ci  } lit_blocks;
5471cb0ef41Sopenharmony_ci  BlockSplitterCommand cmd_blocks;
5481cb0ef41Sopenharmony_ci  BlockSplitterDistance dist_blocks;
5491cb0ef41Sopenharmony_ci  size_t num_literals = 0;
5501cb0ef41Sopenharmony_ci  size_t i;
5511cb0ef41Sopenharmony_ci  for (i = 0; i < n_commands; ++i) {
5521cb0ef41Sopenharmony_ci    num_literals += commands[i].insert_len_;
5531cb0ef41Sopenharmony_ci  }
5541cb0ef41Sopenharmony_ci
5551cb0ef41Sopenharmony_ci  if (num_contexts == 1) {
5561cb0ef41Sopenharmony_ci    InitBlockSplitterLiteral(m, &lit_blocks.plain, 256, 512, 400.0,
5571cb0ef41Sopenharmony_ci        num_literals, &mb->literal_split, &mb->literal_histograms,
5581cb0ef41Sopenharmony_ci        &mb->literal_histograms_size);
5591cb0ef41Sopenharmony_ci  } else {
5601cb0ef41Sopenharmony_ci    InitContextBlockSplitter(m, &lit_blocks.ctx, 256, num_contexts, 512, 400.0,
5611cb0ef41Sopenharmony_ci        num_literals, &mb->literal_split, &mb->literal_histograms,
5621cb0ef41Sopenharmony_ci        &mb->literal_histograms_size);
5631cb0ef41Sopenharmony_ci  }
5641cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m)) return;
5651cb0ef41Sopenharmony_ci  InitBlockSplitterCommand(m, &cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS, 1024,
5661cb0ef41Sopenharmony_ci      500.0, n_commands, &mb->command_split, &mb->command_histograms,
5671cb0ef41Sopenharmony_ci      &mb->command_histograms_size);
5681cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m)) return;
5691cb0ef41Sopenharmony_ci  InitBlockSplitterDistance(m, &dist_blocks, 64, 512, 100.0, n_commands,
5701cb0ef41Sopenharmony_ci      &mb->distance_split, &mb->distance_histograms,
5711cb0ef41Sopenharmony_ci      &mb->distance_histograms_size);
5721cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m)) return;
5731cb0ef41Sopenharmony_ci
5741cb0ef41Sopenharmony_ci  for (i = 0; i < n_commands; ++i) {
5751cb0ef41Sopenharmony_ci    const Command cmd = commands[i];
5761cb0ef41Sopenharmony_ci    size_t j;
5771cb0ef41Sopenharmony_ci    BlockSplitterAddSymbolCommand(&cmd_blocks, cmd.cmd_prefix_);
5781cb0ef41Sopenharmony_ci    for (j = cmd.insert_len_; j != 0; --j) {
5791cb0ef41Sopenharmony_ci      uint8_t literal = ringbuffer[pos & mask];
5801cb0ef41Sopenharmony_ci      if (num_contexts == 1) {
5811cb0ef41Sopenharmony_ci        BlockSplitterAddSymbolLiteral(&lit_blocks.plain, literal);
5821cb0ef41Sopenharmony_ci      } else {
5831cb0ef41Sopenharmony_ci        size_t context =
5841cb0ef41Sopenharmony_ci            BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
5851cb0ef41Sopenharmony_ci        ContextBlockSplitterAddSymbol(&lit_blocks.ctx, m, literal,
5861cb0ef41Sopenharmony_ci                                      static_context_map[context]);
5871cb0ef41Sopenharmony_ci        if (BROTLI_IS_OOM(m)) return;
5881cb0ef41Sopenharmony_ci      }
5891cb0ef41Sopenharmony_ci      prev_byte2 = prev_byte;
5901cb0ef41Sopenharmony_ci      prev_byte = literal;
5911cb0ef41Sopenharmony_ci      ++pos;
5921cb0ef41Sopenharmony_ci    }
5931cb0ef41Sopenharmony_ci    pos += CommandCopyLen(&cmd);
5941cb0ef41Sopenharmony_ci    if (CommandCopyLen(&cmd)) {
5951cb0ef41Sopenharmony_ci      prev_byte2 = ringbuffer[(pos - 2) & mask];
5961cb0ef41Sopenharmony_ci      prev_byte = ringbuffer[(pos - 1) & mask];
5971cb0ef41Sopenharmony_ci      if (cmd.cmd_prefix_ >= 128) {
5981cb0ef41Sopenharmony_ci        BlockSplitterAddSymbolDistance(&dist_blocks, cmd.dist_prefix_ & 0x3FF);
5991cb0ef41Sopenharmony_ci      }
6001cb0ef41Sopenharmony_ci    }
6011cb0ef41Sopenharmony_ci  }
6021cb0ef41Sopenharmony_ci
6031cb0ef41Sopenharmony_ci  if (num_contexts == 1) {
6041cb0ef41Sopenharmony_ci    BlockSplitterFinishBlockLiteral(
6051cb0ef41Sopenharmony_ci        &lit_blocks.plain, /* is_final = */ BROTLI_TRUE);
6061cb0ef41Sopenharmony_ci  } else {
6071cb0ef41Sopenharmony_ci    ContextBlockSplitterFinishBlock(
6081cb0ef41Sopenharmony_ci        &lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE);
6091cb0ef41Sopenharmony_ci    if (BROTLI_IS_OOM(m)) return;
6101cb0ef41Sopenharmony_ci  }
6111cb0ef41Sopenharmony_ci  BlockSplitterFinishBlockCommand(&cmd_blocks, /* is_final = */ BROTLI_TRUE);
6121cb0ef41Sopenharmony_ci  BlockSplitterFinishBlockDistance(&dist_blocks, /* is_final = */ BROTLI_TRUE);
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_ci  if (num_contexts > 1) {
6151cb0ef41Sopenharmony_ci    MapStaticContexts(m, num_contexts, static_context_map, mb);
6161cb0ef41Sopenharmony_ci  }
6171cb0ef41Sopenharmony_ci}
6181cb0ef41Sopenharmony_ci
6191cb0ef41Sopenharmony_civoid BrotliBuildMetaBlockGreedy(MemoryManager* m,
6201cb0ef41Sopenharmony_ci                                const uint8_t* ringbuffer,
6211cb0ef41Sopenharmony_ci                                size_t pos,
6221cb0ef41Sopenharmony_ci                                size_t mask,
6231cb0ef41Sopenharmony_ci                                uint8_t prev_byte,
6241cb0ef41Sopenharmony_ci                                uint8_t prev_byte2,
6251cb0ef41Sopenharmony_ci                                ContextLut literal_context_lut,
6261cb0ef41Sopenharmony_ci                                size_t num_contexts,
6271cb0ef41Sopenharmony_ci                                const uint32_t* static_context_map,
6281cb0ef41Sopenharmony_ci                                const Command* commands,
6291cb0ef41Sopenharmony_ci                                size_t n_commands,
6301cb0ef41Sopenharmony_ci                                MetaBlockSplit* mb) {
6311cb0ef41Sopenharmony_ci  if (num_contexts == 1) {
6321cb0ef41Sopenharmony_ci    BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
6331cb0ef41Sopenharmony_ci        prev_byte2, literal_context_lut, 1, NULL, commands, n_commands, mb);
6341cb0ef41Sopenharmony_ci  } else {
6351cb0ef41Sopenharmony_ci    BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
6361cb0ef41Sopenharmony_ci        prev_byte2, literal_context_lut, num_contexts, static_context_map,
6371cb0ef41Sopenharmony_ci        commands, n_commands, mb);
6381cb0ef41Sopenharmony_ci  }
6391cb0ef41Sopenharmony_ci}
6401cb0ef41Sopenharmony_ci
6411cb0ef41Sopenharmony_civoid BrotliOptimizeHistograms(uint32_t num_distance_codes,
6421cb0ef41Sopenharmony_ci                              MetaBlockSplit* mb) {
6431cb0ef41Sopenharmony_ci  uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS];
6441cb0ef41Sopenharmony_ci  size_t i;
6451cb0ef41Sopenharmony_ci  for (i = 0; i < mb->literal_histograms_size; ++i) {
6461cb0ef41Sopenharmony_ci    BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_,
6471cb0ef41Sopenharmony_ci                                      good_for_rle);
6481cb0ef41Sopenharmony_ci  }
6491cb0ef41Sopenharmony_ci  for (i = 0; i < mb->command_histograms_size; ++i) {
6501cb0ef41Sopenharmony_ci    BrotliOptimizeHuffmanCountsForRle(BROTLI_NUM_COMMAND_SYMBOLS,
6511cb0ef41Sopenharmony_ci                                      mb->command_histograms[i].data_,
6521cb0ef41Sopenharmony_ci                                      good_for_rle);
6531cb0ef41Sopenharmony_ci  }
6541cb0ef41Sopenharmony_ci  for (i = 0; i < mb->distance_histograms_size; ++i) {
6551cb0ef41Sopenharmony_ci    BrotliOptimizeHuffmanCountsForRle(num_distance_codes,
6561cb0ef41Sopenharmony_ci                                      mb->distance_histograms[i].data_,
6571cb0ef41Sopenharmony_ci                                      good_for_rle);
6581cb0ef41Sopenharmony_ci  }
6591cb0ef41Sopenharmony_ci}
6601cb0ef41Sopenharmony_ci
6611cb0ef41Sopenharmony_ci#if defined(__cplusplus) || defined(c_plusplus)
6621cb0ef41Sopenharmony_ci}  /* extern "C" */
6631cb0ef41Sopenharmony_ci#endif
664