11cb0ef41Sopenharmony_ci/* NOLINT(build/header_guard) */
21cb0ef41Sopenharmony_ci/* Copyright 2013 Google Inc. All Rights Reserved.
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ci   Distributed under MIT license.
51cb0ef41Sopenharmony_ci   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
61cb0ef41Sopenharmony_ci*/
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci/* template parameters: FN, CODE */
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci#define HistogramType FN(Histogram)
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
131cb0ef41Sopenharmony_ci   it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
141cb0ef41Sopenharmony_ciBROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
151cb0ef41Sopenharmony_ci    const HistogramType* out, const uint32_t* cluster_size, uint32_t idx1,
161cb0ef41Sopenharmony_ci    uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs,
171cb0ef41Sopenharmony_ci    size_t* num_pairs) CODE({
181cb0ef41Sopenharmony_ci  BROTLI_BOOL is_good_pair = BROTLI_FALSE;
191cb0ef41Sopenharmony_ci  HistogramPair p;
201cb0ef41Sopenharmony_ci  p.idx1 = p.idx2 = 0;
211cb0ef41Sopenharmony_ci  p.cost_diff = p.cost_combo = 0;
221cb0ef41Sopenharmony_ci  if (idx1 == idx2) {
231cb0ef41Sopenharmony_ci    return;
241cb0ef41Sopenharmony_ci  }
251cb0ef41Sopenharmony_ci  if (idx2 < idx1) {
261cb0ef41Sopenharmony_ci    uint32_t t = idx2;
271cb0ef41Sopenharmony_ci    idx2 = idx1;
281cb0ef41Sopenharmony_ci    idx1 = t;
291cb0ef41Sopenharmony_ci  }
301cb0ef41Sopenharmony_ci  p.idx1 = idx1;
311cb0ef41Sopenharmony_ci  p.idx2 = idx2;
321cb0ef41Sopenharmony_ci  p.cost_diff = 0.5 * ClusterCostDiff(cluster_size[idx1], cluster_size[idx2]);
331cb0ef41Sopenharmony_ci  p.cost_diff -= out[idx1].bit_cost_;
341cb0ef41Sopenharmony_ci  p.cost_diff -= out[idx2].bit_cost_;
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  if (out[idx1].total_count_ == 0) {
371cb0ef41Sopenharmony_ci    p.cost_combo = out[idx2].bit_cost_;
381cb0ef41Sopenharmony_ci    is_good_pair = BROTLI_TRUE;
391cb0ef41Sopenharmony_ci  } else if (out[idx2].total_count_ == 0) {
401cb0ef41Sopenharmony_ci    p.cost_combo = out[idx1].bit_cost_;
411cb0ef41Sopenharmony_ci    is_good_pair = BROTLI_TRUE;
421cb0ef41Sopenharmony_ci  } else {
431cb0ef41Sopenharmony_ci    double threshold = *num_pairs == 0 ? 1e99 :
441cb0ef41Sopenharmony_ci        BROTLI_MAX(double, 0.0, pairs[0].cost_diff);
451cb0ef41Sopenharmony_ci    HistogramType combo = out[idx1];
461cb0ef41Sopenharmony_ci    double cost_combo;
471cb0ef41Sopenharmony_ci    FN(HistogramAddHistogram)(&combo, &out[idx2]);
481cb0ef41Sopenharmony_ci    cost_combo = FN(BrotliPopulationCost)(&combo);
491cb0ef41Sopenharmony_ci    if (cost_combo < threshold - p.cost_diff) {
501cb0ef41Sopenharmony_ci      p.cost_combo = cost_combo;
511cb0ef41Sopenharmony_ci      is_good_pair = BROTLI_TRUE;
521cb0ef41Sopenharmony_ci    }
531cb0ef41Sopenharmony_ci  }
541cb0ef41Sopenharmony_ci  if (is_good_pair) {
551cb0ef41Sopenharmony_ci    p.cost_diff += p.cost_combo;
561cb0ef41Sopenharmony_ci    if (*num_pairs > 0 && HistogramPairIsLess(&pairs[0], &p)) {
571cb0ef41Sopenharmony_ci      /* Replace the top of the queue if needed. */
581cb0ef41Sopenharmony_ci      if (*num_pairs < max_num_pairs) {
591cb0ef41Sopenharmony_ci        pairs[*num_pairs] = pairs[0];
601cb0ef41Sopenharmony_ci        ++(*num_pairs);
611cb0ef41Sopenharmony_ci      }
621cb0ef41Sopenharmony_ci      pairs[0] = p;
631cb0ef41Sopenharmony_ci    } else if (*num_pairs < max_num_pairs) {
641cb0ef41Sopenharmony_ci      pairs[*num_pairs] = p;
651cb0ef41Sopenharmony_ci      ++(*num_pairs);
661cb0ef41Sopenharmony_ci    }
671cb0ef41Sopenharmony_ci  }
681cb0ef41Sopenharmony_ci})
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ciBROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
711cb0ef41Sopenharmony_ci                                                  uint32_t* cluster_size,
721cb0ef41Sopenharmony_ci                                                  uint32_t* symbols,
731cb0ef41Sopenharmony_ci                                                  uint32_t* clusters,
741cb0ef41Sopenharmony_ci                                                  HistogramPair* pairs,
751cb0ef41Sopenharmony_ci                                                  size_t num_clusters,
761cb0ef41Sopenharmony_ci                                                  size_t symbols_size,
771cb0ef41Sopenharmony_ci                                                  size_t max_clusters,
781cb0ef41Sopenharmony_ci                                                  size_t max_num_pairs) CODE({
791cb0ef41Sopenharmony_ci  double cost_diff_threshold = 0.0;
801cb0ef41Sopenharmony_ci  size_t min_cluster_size = 1;
811cb0ef41Sopenharmony_ci  size_t num_pairs = 0;
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  {
841cb0ef41Sopenharmony_ci    /* We maintain a vector of histogram pairs, with the property that the pair
851cb0ef41Sopenharmony_ci       with the maximum bit cost reduction is the first. */
861cb0ef41Sopenharmony_ci    size_t idx1;
871cb0ef41Sopenharmony_ci    for (idx1 = 0; idx1 < num_clusters; ++idx1) {
881cb0ef41Sopenharmony_ci      size_t idx2;
891cb0ef41Sopenharmony_ci      for (idx2 = idx1 + 1; idx2 < num_clusters; ++idx2) {
901cb0ef41Sopenharmony_ci        FN(BrotliCompareAndPushToQueue)(out, cluster_size, clusters[idx1],
911cb0ef41Sopenharmony_ci            clusters[idx2], max_num_pairs, &pairs[0], &num_pairs);
921cb0ef41Sopenharmony_ci      }
931cb0ef41Sopenharmony_ci    }
941cb0ef41Sopenharmony_ci  }
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci  while (num_clusters > min_cluster_size) {
971cb0ef41Sopenharmony_ci    uint32_t best_idx1;
981cb0ef41Sopenharmony_ci    uint32_t best_idx2;
991cb0ef41Sopenharmony_ci    size_t i;
1001cb0ef41Sopenharmony_ci    if (pairs[0].cost_diff >= cost_diff_threshold) {
1011cb0ef41Sopenharmony_ci      cost_diff_threshold = 1e99;
1021cb0ef41Sopenharmony_ci      min_cluster_size = max_clusters;
1031cb0ef41Sopenharmony_ci      continue;
1041cb0ef41Sopenharmony_ci    }
1051cb0ef41Sopenharmony_ci    /* Take the best pair from the top of heap. */
1061cb0ef41Sopenharmony_ci    best_idx1 = pairs[0].idx1;
1071cb0ef41Sopenharmony_ci    best_idx2 = pairs[0].idx2;
1081cb0ef41Sopenharmony_ci    FN(HistogramAddHistogram)(&out[best_idx1], &out[best_idx2]);
1091cb0ef41Sopenharmony_ci    out[best_idx1].bit_cost_ = pairs[0].cost_combo;
1101cb0ef41Sopenharmony_ci    cluster_size[best_idx1] += cluster_size[best_idx2];
1111cb0ef41Sopenharmony_ci    for (i = 0; i < symbols_size; ++i) {
1121cb0ef41Sopenharmony_ci      if (symbols[i] == best_idx2) {
1131cb0ef41Sopenharmony_ci        symbols[i] = best_idx1;
1141cb0ef41Sopenharmony_ci      }
1151cb0ef41Sopenharmony_ci    }
1161cb0ef41Sopenharmony_ci    for (i = 0; i < num_clusters; ++i) {
1171cb0ef41Sopenharmony_ci      if (clusters[i] == best_idx2) {
1181cb0ef41Sopenharmony_ci        memmove(&clusters[i], &clusters[i + 1],
1191cb0ef41Sopenharmony_ci                (num_clusters - i - 1) * sizeof(clusters[0]));
1201cb0ef41Sopenharmony_ci        break;
1211cb0ef41Sopenharmony_ci      }
1221cb0ef41Sopenharmony_ci    }
1231cb0ef41Sopenharmony_ci    --num_clusters;
1241cb0ef41Sopenharmony_ci    {
1251cb0ef41Sopenharmony_ci      /* Remove pairs intersecting the just combined best pair. */
1261cb0ef41Sopenharmony_ci      size_t copy_to_idx = 0;
1271cb0ef41Sopenharmony_ci      for (i = 0; i < num_pairs; ++i) {
1281cb0ef41Sopenharmony_ci        HistogramPair* p = &pairs[i];
1291cb0ef41Sopenharmony_ci        if (p->idx1 == best_idx1 || p->idx2 == best_idx1 ||
1301cb0ef41Sopenharmony_ci            p->idx1 == best_idx2 || p->idx2 == best_idx2) {
1311cb0ef41Sopenharmony_ci          /* Remove invalid pair from the queue. */
1321cb0ef41Sopenharmony_ci          continue;
1331cb0ef41Sopenharmony_ci        }
1341cb0ef41Sopenharmony_ci        if (HistogramPairIsLess(&pairs[0], p)) {
1351cb0ef41Sopenharmony_ci          /* Replace the top of the queue if needed. */
1361cb0ef41Sopenharmony_ci          HistogramPair front = pairs[0];
1371cb0ef41Sopenharmony_ci          pairs[0] = *p;
1381cb0ef41Sopenharmony_ci          pairs[copy_to_idx] = front;
1391cb0ef41Sopenharmony_ci        } else {
1401cb0ef41Sopenharmony_ci          pairs[copy_to_idx] = *p;
1411cb0ef41Sopenharmony_ci        }
1421cb0ef41Sopenharmony_ci        ++copy_to_idx;
1431cb0ef41Sopenharmony_ci      }
1441cb0ef41Sopenharmony_ci      num_pairs = copy_to_idx;
1451cb0ef41Sopenharmony_ci    }
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci    /* Push new pairs formed with the combined histogram to the heap. */
1481cb0ef41Sopenharmony_ci    for (i = 0; i < num_clusters; ++i) {
1491cb0ef41Sopenharmony_ci      FN(BrotliCompareAndPushToQueue)(out, cluster_size, best_idx1, clusters[i],
1501cb0ef41Sopenharmony_ci                                      max_num_pairs, &pairs[0], &num_pairs);
1511cb0ef41Sopenharmony_ci    }
1521cb0ef41Sopenharmony_ci  }
1531cb0ef41Sopenharmony_ci  return num_clusters;
1541cb0ef41Sopenharmony_ci})
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci/* What is the bit cost of moving histogram from cur_symbol to candidate. */
1571cb0ef41Sopenharmony_ciBROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)(
1581cb0ef41Sopenharmony_ci    const HistogramType* histogram, const HistogramType* candidate) CODE({
1591cb0ef41Sopenharmony_ci  if (histogram->total_count_ == 0) {
1601cb0ef41Sopenharmony_ci    return 0.0;
1611cb0ef41Sopenharmony_ci  } else {
1621cb0ef41Sopenharmony_ci    HistogramType tmp = *histogram;
1631cb0ef41Sopenharmony_ci    FN(HistogramAddHistogram)(&tmp, candidate);
1641cb0ef41Sopenharmony_ci    return FN(BrotliPopulationCost)(&tmp) - candidate->bit_cost_;
1651cb0ef41Sopenharmony_ci  }
1661cb0ef41Sopenharmony_ci})
1671cb0ef41Sopenharmony_ci
1681cb0ef41Sopenharmony_ci/* Find the best 'out' histogram for each of the 'in' histograms.
1691cb0ef41Sopenharmony_ci   When called, clusters[0..num_clusters) contains the unique values from
1701cb0ef41Sopenharmony_ci   symbols[0..in_size), but this property is not preserved in this function.
1711cb0ef41Sopenharmony_ci   Note: we assume that out[]->bit_cost_ is already up-to-date. */
1721cb0ef41Sopenharmony_ciBROTLI_INTERNAL void FN(BrotliHistogramRemap)(const HistogramType* in,
1731cb0ef41Sopenharmony_ci    size_t in_size, const uint32_t* clusters, size_t num_clusters,
1741cb0ef41Sopenharmony_ci    HistogramType* out, uint32_t* symbols) CODE({
1751cb0ef41Sopenharmony_ci  size_t i;
1761cb0ef41Sopenharmony_ci  for (i = 0; i < in_size; ++i) {
1771cb0ef41Sopenharmony_ci    uint32_t best_out = i == 0 ? symbols[0] : symbols[i - 1];
1781cb0ef41Sopenharmony_ci    double best_bits =
1791cb0ef41Sopenharmony_ci        FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out]);
1801cb0ef41Sopenharmony_ci    size_t j;
1811cb0ef41Sopenharmony_ci    for (j = 0; j < num_clusters; ++j) {
1821cb0ef41Sopenharmony_ci      const double cur_bits =
1831cb0ef41Sopenharmony_ci          FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]]);
1841cb0ef41Sopenharmony_ci      if (cur_bits < best_bits) {
1851cb0ef41Sopenharmony_ci        best_bits = cur_bits;
1861cb0ef41Sopenharmony_ci        best_out = clusters[j];
1871cb0ef41Sopenharmony_ci      }
1881cb0ef41Sopenharmony_ci    }
1891cb0ef41Sopenharmony_ci    symbols[i] = best_out;
1901cb0ef41Sopenharmony_ci  }
1911cb0ef41Sopenharmony_ci
1921cb0ef41Sopenharmony_ci  /* Recompute each out based on raw and symbols. */
1931cb0ef41Sopenharmony_ci  for (i = 0; i < num_clusters; ++i) {
1941cb0ef41Sopenharmony_ci    FN(HistogramClear)(&out[clusters[i]]);
1951cb0ef41Sopenharmony_ci  }
1961cb0ef41Sopenharmony_ci  for (i = 0; i < in_size; ++i) {
1971cb0ef41Sopenharmony_ci    FN(HistogramAddHistogram)(&out[symbols[i]], &in[i]);
1981cb0ef41Sopenharmony_ci  }
1991cb0ef41Sopenharmony_ci})
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci/* Reorders elements of the out[0..length) array and changes values in
2021cb0ef41Sopenharmony_ci   symbols[0..length) array in the following way:
2031cb0ef41Sopenharmony_ci     * when called, symbols[] contains indexes into out[], and has N unique
2041cb0ef41Sopenharmony_ci       values (possibly N < length)
2051cb0ef41Sopenharmony_ci     * on return, symbols'[i] = f(symbols[i]) and
2061cb0ef41Sopenharmony_ci                  out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length,
2071cb0ef41Sopenharmony_ci       where f is a bijection between the range of symbols[] and [0..N), and
2081cb0ef41Sopenharmony_ci       the first occurrences of values in symbols'[i] come in consecutive
2091cb0ef41Sopenharmony_ci       increasing order.
2101cb0ef41Sopenharmony_ci   Returns N, the number of unique values in symbols[]. */
2111cb0ef41Sopenharmony_ciBROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
2121cb0ef41Sopenharmony_ci    HistogramType* out, uint32_t* symbols, size_t length) CODE({
2131cb0ef41Sopenharmony_ci  static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX;
2141cb0ef41Sopenharmony_ci  uint32_t* new_index = BROTLI_ALLOC(m, uint32_t, length);
2151cb0ef41Sopenharmony_ci  uint32_t next_index;
2161cb0ef41Sopenharmony_ci  HistogramType* tmp;
2171cb0ef41Sopenharmony_ci  size_t i;
2181cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0;
2191cb0ef41Sopenharmony_ci  for (i = 0; i < length; ++i) {
2201cb0ef41Sopenharmony_ci      new_index[i] = kInvalidIndex;
2211cb0ef41Sopenharmony_ci  }
2221cb0ef41Sopenharmony_ci  next_index = 0;
2231cb0ef41Sopenharmony_ci  for (i = 0; i < length; ++i) {
2241cb0ef41Sopenharmony_ci    if (new_index[symbols[i]] == kInvalidIndex) {
2251cb0ef41Sopenharmony_ci      new_index[symbols[i]] = next_index;
2261cb0ef41Sopenharmony_ci      ++next_index;
2271cb0ef41Sopenharmony_ci    }
2281cb0ef41Sopenharmony_ci  }
2291cb0ef41Sopenharmony_ci  /* TODO: by using idea of "cycle-sort" we can avoid allocation of
2301cb0ef41Sopenharmony_ci     tmp and reduce the number of copying by the factor of 2. */
2311cb0ef41Sopenharmony_ci  tmp = BROTLI_ALLOC(m, HistogramType, next_index);
2321cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0;
2331cb0ef41Sopenharmony_ci  next_index = 0;
2341cb0ef41Sopenharmony_ci  for (i = 0; i < length; ++i) {
2351cb0ef41Sopenharmony_ci    if (new_index[symbols[i]] == next_index) {
2361cb0ef41Sopenharmony_ci      tmp[next_index] = out[symbols[i]];
2371cb0ef41Sopenharmony_ci      ++next_index;
2381cb0ef41Sopenharmony_ci    }
2391cb0ef41Sopenharmony_ci    symbols[i] = new_index[symbols[i]];
2401cb0ef41Sopenharmony_ci  }
2411cb0ef41Sopenharmony_ci  BROTLI_FREE(m, new_index);
2421cb0ef41Sopenharmony_ci  for (i = 0; i < next_index; ++i) {
2431cb0ef41Sopenharmony_ci    out[i] = tmp[i];
2441cb0ef41Sopenharmony_ci  }
2451cb0ef41Sopenharmony_ci  BROTLI_FREE(m, tmp);
2461cb0ef41Sopenharmony_ci  return next_index;
2471cb0ef41Sopenharmony_ci})
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_ciBROTLI_INTERNAL void FN(BrotliClusterHistograms)(
2501cb0ef41Sopenharmony_ci    MemoryManager* m, const HistogramType* in, const size_t in_size,
2511cb0ef41Sopenharmony_ci    size_t max_histograms, HistogramType* out, size_t* out_size,
2521cb0ef41Sopenharmony_ci    uint32_t* histogram_symbols) CODE({
2531cb0ef41Sopenharmony_ci  uint32_t* cluster_size = BROTLI_ALLOC(m, uint32_t, in_size);
2541cb0ef41Sopenharmony_ci  uint32_t* clusters = BROTLI_ALLOC(m, uint32_t, in_size);
2551cb0ef41Sopenharmony_ci  size_t num_clusters = 0;
2561cb0ef41Sopenharmony_ci  const size_t max_input_histograms = 64;
2571cb0ef41Sopenharmony_ci  size_t pairs_capacity = max_input_histograms * max_input_histograms / 2;
2581cb0ef41Sopenharmony_ci  /* For the first pass of clustering, we allow all pairs. */
2591cb0ef41Sopenharmony_ci  HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
2601cb0ef41Sopenharmony_ci  size_t i;
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) ||
2631cb0ef41Sopenharmony_ci      BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)) {
2641cb0ef41Sopenharmony_ci    return;
2651cb0ef41Sopenharmony_ci  }
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci  for (i = 0; i < in_size; ++i) {
2681cb0ef41Sopenharmony_ci    cluster_size[i] = 1;
2691cb0ef41Sopenharmony_ci  }
2701cb0ef41Sopenharmony_ci
2711cb0ef41Sopenharmony_ci  for (i = 0; i < in_size; ++i) {
2721cb0ef41Sopenharmony_ci    out[i] = in[i];
2731cb0ef41Sopenharmony_ci    out[i].bit_cost_ = FN(BrotliPopulationCost)(&in[i]);
2741cb0ef41Sopenharmony_ci    histogram_symbols[i] = (uint32_t)i;
2751cb0ef41Sopenharmony_ci  }
2761cb0ef41Sopenharmony_ci
2771cb0ef41Sopenharmony_ci  for (i = 0; i < in_size; i += max_input_histograms) {
2781cb0ef41Sopenharmony_ci    size_t num_to_combine =
2791cb0ef41Sopenharmony_ci        BROTLI_MIN(size_t, in_size - i, max_input_histograms);
2801cb0ef41Sopenharmony_ci    size_t num_new_clusters;
2811cb0ef41Sopenharmony_ci    size_t j;
2821cb0ef41Sopenharmony_ci    for (j = 0; j < num_to_combine; ++j) {
2831cb0ef41Sopenharmony_ci      clusters[num_clusters + j] = (uint32_t)(i + j);
2841cb0ef41Sopenharmony_ci    }
2851cb0ef41Sopenharmony_ci    num_new_clusters =
2861cb0ef41Sopenharmony_ci        FN(BrotliHistogramCombine)(out, cluster_size,
2871cb0ef41Sopenharmony_ci                                   &histogram_symbols[i],
2881cb0ef41Sopenharmony_ci                                   &clusters[num_clusters], pairs,
2891cb0ef41Sopenharmony_ci                                   num_to_combine, num_to_combine,
2901cb0ef41Sopenharmony_ci                                   max_histograms, pairs_capacity);
2911cb0ef41Sopenharmony_ci    num_clusters += num_new_clusters;
2921cb0ef41Sopenharmony_ci  }
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci  {
2951cb0ef41Sopenharmony_ci    /* For the second pass, we limit the total number of histogram pairs.
2961cb0ef41Sopenharmony_ci       After this limit is reached, we only keep searching for the best pair. */
2971cb0ef41Sopenharmony_ci    size_t max_num_pairs = BROTLI_MIN(size_t,
2981cb0ef41Sopenharmony_ci        64 * num_clusters, (num_clusters / 2) * num_clusters);
2991cb0ef41Sopenharmony_ci    BROTLI_ENSURE_CAPACITY(
3001cb0ef41Sopenharmony_ci        m, HistogramPair, pairs, pairs_capacity, max_num_pairs + 1);
3011cb0ef41Sopenharmony_ci    if (BROTLI_IS_OOM(m)) return;
3021cb0ef41Sopenharmony_ci
3031cb0ef41Sopenharmony_ci    /* Collapse similar histograms. */
3041cb0ef41Sopenharmony_ci    num_clusters = FN(BrotliHistogramCombine)(out, cluster_size,
3051cb0ef41Sopenharmony_ci                                              histogram_symbols, clusters,
3061cb0ef41Sopenharmony_ci                                              pairs, num_clusters, in_size,
3071cb0ef41Sopenharmony_ci                                              max_histograms, max_num_pairs);
3081cb0ef41Sopenharmony_ci  }
3091cb0ef41Sopenharmony_ci  BROTLI_FREE(m, pairs);
3101cb0ef41Sopenharmony_ci  BROTLI_FREE(m, cluster_size);
3111cb0ef41Sopenharmony_ci  /* Find the optimal map from original histograms to the final ones. */
3121cb0ef41Sopenharmony_ci  FN(BrotliHistogramRemap)(in, in_size, clusters, num_clusters,
3131cb0ef41Sopenharmony_ci                           out, histogram_symbols);
3141cb0ef41Sopenharmony_ci  BROTLI_FREE(m, clusters);
3151cb0ef41Sopenharmony_ci  /* Convert the context map to a canonical form. */
3161cb0ef41Sopenharmony_ci  *out_size = FN(BrotliHistogramReindex)(m, out, histogram_symbols, in_size);
3171cb0ef41Sopenharmony_ci  if (BROTLI_IS_OOM(m)) return;
3181cb0ef41Sopenharmony_ci})
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ci#undef HistogramType
321