126fa459cSmrg/* Copyright 2013 Google Inc. All Rights Reserved.
226fa459cSmrg
326fa459cSmrg   Distributed under MIT license.
426fa459cSmrg   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
526fa459cSmrg*/
626fa459cSmrg
726fa459cSmrg/* Function to find backward reference copies. */
826fa459cSmrg
926fa459cSmrg#include "./backward_references_hq.h"
1026fa459cSmrg
1126fa459cSmrg#include <string.h>  /* memcpy, memset */
1226fa459cSmrg
1326fa459cSmrg#include "../common/constants.h"
1426fa459cSmrg#include "../common/context.h"
1526fa459cSmrg#include "../common/platform.h"
1626fa459cSmrg#include <brotli/types.h>
1726fa459cSmrg#include "./command.h"
1826fa459cSmrg#include "./fast_log.h"
1926fa459cSmrg#include "./find_match_length.h"
2026fa459cSmrg#include "./literal_cost.h"
2126fa459cSmrg#include "./memory.h"
2226fa459cSmrg#include "./params.h"
2326fa459cSmrg#include "./prefix.h"
2426fa459cSmrg#include "./quality.h"
2526fa459cSmrg
2626fa459cSmrg#if defined(__cplusplus) || defined(c_plusplus)
2726fa459cSmrgextern "C" {
2826fa459cSmrg#endif
2926fa459cSmrg
3026fa459cSmrg/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
3126fa459cSmrg#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
3226fa459cSmrg
3326fa459cSmrgstatic const float kInfinity = 1.7e38f;  /* ~= 2 ^ 127 */
3426fa459cSmrg
3526fa459cSmrgstatic const uint32_t kDistanceCacheIndex[] = {
3626fa459cSmrg  0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
3726fa459cSmrg};
3826fa459cSmrgstatic const int kDistanceCacheOffset[] = {
3926fa459cSmrg  0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3
4026fa459cSmrg};
4126fa459cSmrg
4226fa459cSmrgvoid BrotliInitZopfliNodes(ZopfliNode* array, size_t length) {
4326fa459cSmrg  ZopfliNode stub;
4426fa459cSmrg  size_t i;
4526fa459cSmrg  stub.length = 1;
4626fa459cSmrg  stub.distance = 0;
4726fa459cSmrg  stub.dcode_insert_length = 0;
4826fa459cSmrg  stub.u.cost = kInfinity;
4926fa459cSmrg  for (i = 0; i < length; ++i) array[i] = stub;
5026fa459cSmrg}
5126fa459cSmrg
5226fa459cSmrgstatic BROTLI_INLINE uint32_t ZopfliNodeCopyLength(const ZopfliNode* self) {
5326fa459cSmrg  return self->length & 0x1FFFFFF;
5426fa459cSmrg}
5526fa459cSmrg
5626fa459cSmrgstatic BROTLI_INLINE uint32_t ZopfliNodeLengthCode(const ZopfliNode* self) {
5726fa459cSmrg  const uint32_t modifier = self->length >> 25;
5826fa459cSmrg  return ZopfliNodeCopyLength(self) + 9u - modifier;
5926fa459cSmrg}
6026fa459cSmrg
6126fa459cSmrgstatic BROTLI_INLINE uint32_t ZopfliNodeCopyDistance(const ZopfliNode* self) {
6226fa459cSmrg  return self->distance;
6326fa459cSmrg}
6426fa459cSmrg
6526fa459cSmrgstatic BROTLI_INLINE uint32_t ZopfliNodeDistanceCode(const ZopfliNode* self) {
6626fa459cSmrg  const uint32_t short_code = self->dcode_insert_length >> 27;
6726fa459cSmrg  return short_code == 0 ?
6826fa459cSmrg      ZopfliNodeCopyDistance(self) + BROTLI_NUM_DISTANCE_SHORT_CODES - 1 :
6926fa459cSmrg      short_code - 1;
7026fa459cSmrg}
7126fa459cSmrg
7226fa459cSmrgstatic BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
7326fa459cSmrg  return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF);
7426fa459cSmrg}
7526fa459cSmrg
7626fa459cSmrg/* Histogram based cost model for zopflification. */
7726fa459cSmrgtypedef struct ZopfliCostModel {
7826fa459cSmrg  /* The insert and copy length symbols. */
7926fa459cSmrg  float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS];
8026fa459cSmrg  float* cost_dist_;
8126fa459cSmrg  uint32_t distance_histogram_size;
8226fa459cSmrg  /* Cumulative costs of literals per position in the stream. */
8326fa459cSmrg  float* literal_costs_;
8426fa459cSmrg  float min_cost_cmd_;
8526fa459cSmrg  size_t num_bytes_;
8626fa459cSmrg} ZopfliCostModel;
8726fa459cSmrg
8826fa459cSmrgstatic void InitZopfliCostModel(
8926fa459cSmrg    MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
9026fa459cSmrg    size_t num_bytes) {
9126fa459cSmrg  self->num_bytes_ = num_bytes;
9226fa459cSmrg  self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
9326fa459cSmrg  self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit);
9426fa459cSmrg  self->distance_histogram_size = dist->alphabet_size_limit;
9526fa459cSmrg  if (BROTLI_IS_OOM(m)) return;
9626fa459cSmrg}
9726fa459cSmrg
9826fa459cSmrgstatic void CleanupZopfliCostModel(MemoryManager* m, ZopfliCostModel* self) {
9926fa459cSmrg  BROTLI_FREE(m, self->literal_costs_);
10026fa459cSmrg  BROTLI_FREE(m, self->cost_dist_);
10126fa459cSmrg}
10226fa459cSmrg
10326fa459cSmrgstatic void SetCost(const uint32_t* histogram, size_t histogram_size,
10426fa459cSmrg                    BROTLI_BOOL literal_histogram, float* cost) {
10526fa459cSmrg  size_t sum = 0;
10626fa459cSmrg  size_t missing_symbol_sum;
10726fa459cSmrg  float log2sum;
10826fa459cSmrg  float missing_symbol_cost;
10926fa459cSmrg  size_t i;
11026fa459cSmrg  for (i = 0; i < histogram_size; i++) {
11126fa459cSmrg    sum += histogram[i];
11226fa459cSmrg  }
11326fa459cSmrg  log2sum = (float)FastLog2(sum);
11426fa459cSmrg  missing_symbol_sum = sum;
11526fa459cSmrg  if (!literal_histogram) {
11626fa459cSmrg    for (i = 0; i < histogram_size; i++) {
11726fa459cSmrg      if (histogram[i] == 0) missing_symbol_sum++;
11826fa459cSmrg    }
11926fa459cSmrg  }
12026fa459cSmrg  missing_symbol_cost = (float)FastLog2(missing_symbol_sum) + 2;
12126fa459cSmrg  for (i = 0; i < histogram_size; i++) {
12226fa459cSmrg    if (histogram[i] == 0) {
12326fa459cSmrg      cost[i] = missing_symbol_cost;
12426fa459cSmrg      continue;
12526fa459cSmrg    }
12626fa459cSmrg
12726fa459cSmrg    /* Shannon bits for this symbol. */
12826fa459cSmrg    cost[i] = log2sum - (float)FastLog2(histogram[i]);
12926fa459cSmrg
13026fa459cSmrg    /* Cannot be coded with less than 1 bit */
13126fa459cSmrg    if (cost[i] < 1) cost[i] = 1;
13226fa459cSmrg  }
13326fa459cSmrg}
13426fa459cSmrg
13526fa459cSmrgstatic void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
13626fa459cSmrg                                           size_t position,
13726fa459cSmrg                                           const uint8_t* ringbuffer,
13826fa459cSmrg                                           size_t ringbuffer_mask,
13926fa459cSmrg                                           const Command* commands,
14026fa459cSmrg                                           size_t num_commands,
14126fa459cSmrg                                           size_t last_insert_len) {
14226fa459cSmrg  uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
14326fa459cSmrg  uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
14426fa459cSmrg  uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
14526fa459cSmrg  float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
14626fa459cSmrg  size_t pos = position - last_insert_len;
14726fa459cSmrg  float min_cost_cmd = kInfinity;
14826fa459cSmrg  size_t i;
14926fa459cSmrg  float* cost_cmd = self->cost_cmd_;
15026fa459cSmrg
15126fa459cSmrg  memset(histogram_literal, 0, sizeof(histogram_literal));
15226fa459cSmrg  memset(histogram_cmd, 0, sizeof(histogram_cmd));
15326fa459cSmrg  memset(histogram_dist, 0, sizeof(histogram_dist));
15426fa459cSmrg
15526fa459cSmrg  for (i = 0; i < num_commands; i++) {
15626fa459cSmrg    size_t inslength = commands[i].insert_len_;
15726fa459cSmrg    size_t copylength = CommandCopyLen(&commands[i]);
15826fa459cSmrg    size_t distcode = commands[i].dist_prefix_ & 0x3FF;
15926fa459cSmrg    size_t cmdcode = commands[i].cmd_prefix_;
16026fa459cSmrg    size_t j;
16126fa459cSmrg
16226fa459cSmrg    histogram_cmd[cmdcode]++;
16326fa459cSmrg    if (cmdcode >= 128) histogram_dist[distcode]++;
16426fa459cSmrg
16526fa459cSmrg    for (j = 0; j < inslength; j++) {
16626fa459cSmrg      histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
16726fa459cSmrg    }
16826fa459cSmrg
16926fa459cSmrg    pos += inslength + copylength;
17026fa459cSmrg  }
17126fa459cSmrg
17226fa459cSmrg  SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
17326fa459cSmrg          cost_literal);
17426fa459cSmrg  SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
17526fa459cSmrg          cost_cmd);
17626fa459cSmrg  SetCost(histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
17726fa459cSmrg          self->cost_dist_);
17826fa459cSmrg
17926fa459cSmrg  for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
18026fa459cSmrg    min_cost_cmd = BROTLI_MIN(float, min_cost_cmd, cost_cmd[i]);
18126fa459cSmrg  }
18226fa459cSmrg  self->min_cost_cmd_ = min_cost_cmd;
18326fa459cSmrg
18426fa459cSmrg  {
18526fa459cSmrg    float* literal_costs = self->literal_costs_;
18626fa459cSmrg    float literal_carry = 0.0;
18726fa459cSmrg    size_t num_bytes = self->num_bytes_;
18826fa459cSmrg    literal_costs[0] = 0.0;
18926fa459cSmrg    for (i = 0; i < num_bytes; ++i) {
19026fa459cSmrg      literal_carry +=
19126fa459cSmrg          cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
19226fa459cSmrg      literal_costs[i + 1] = literal_costs[i] + literal_carry;
19326fa459cSmrg      literal_carry -= literal_costs[i + 1] - literal_costs[i];
19426fa459cSmrg    }
19526fa459cSmrg  }
19626fa459cSmrg}
19726fa459cSmrg
19826fa459cSmrgstatic void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
19926fa459cSmrg                                               size_t position,
20026fa459cSmrg                                               const uint8_t* ringbuffer,
20126fa459cSmrg                                               size_t ringbuffer_mask) {
20226fa459cSmrg  float* literal_costs = self->literal_costs_;
20326fa459cSmrg  float literal_carry = 0.0;
20426fa459cSmrg  float* cost_dist = self->cost_dist_;
20526fa459cSmrg  float* cost_cmd = self->cost_cmd_;
20626fa459cSmrg  size_t num_bytes = self->num_bytes_;
20726fa459cSmrg  size_t i;
20826fa459cSmrg  BrotliEstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask,
20926fa459cSmrg                                    ringbuffer, &literal_costs[1]);
21026fa459cSmrg  literal_costs[0] = 0.0;
21126fa459cSmrg  for (i = 0; i < num_bytes; ++i) {
21226fa459cSmrg    literal_carry += literal_costs[i + 1];
21326fa459cSmrg    literal_costs[i + 1] = literal_costs[i] + literal_carry;
21426fa459cSmrg    literal_carry -= literal_costs[i + 1] - literal_costs[i];
21526fa459cSmrg  }
21626fa459cSmrg  for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
21726fa459cSmrg    cost_cmd[i] = (float)FastLog2(11 + (uint32_t)i);
21826fa459cSmrg  }
21926fa459cSmrg  for (i = 0; i < self->distance_histogram_size; ++i) {
22026fa459cSmrg    cost_dist[i] = (float)FastLog2(20 + (uint32_t)i);
22126fa459cSmrg  }
22226fa459cSmrg  self->min_cost_cmd_ = (float)FastLog2(11);
22326fa459cSmrg}
22426fa459cSmrg
22526fa459cSmrgstatic BROTLI_INLINE float ZopfliCostModelGetCommandCost(
22626fa459cSmrg    const ZopfliCostModel* self, uint16_t cmdcode) {
22726fa459cSmrg  return self->cost_cmd_[cmdcode];
22826fa459cSmrg}
22926fa459cSmrg
23026fa459cSmrgstatic BROTLI_INLINE float ZopfliCostModelGetDistanceCost(
23126fa459cSmrg    const ZopfliCostModel* self, size_t distcode) {
23226fa459cSmrg  return self->cost_dist_[distcode];
23326fa459cSmrg}
23426fa459cSmrg
23526fa459cSmrgstatic BROTLI_INLINE float ZopfliCostModelGetLiteralCosts(
23626fa459cSmrg    const ZopfliCostModel* self, size_t from, size_t to) {
23726fa459cSmrg  return self->literal_costs_[to] - self->literal_costs_[from];
23826fa459cSmrg}
23926fa459cSmrg
24026fa459cSmrgstatic BROTLI_INLINE float ZopfliCostModelGetMinCostCmd(
24126fa459cSmrg    const ZopfliCostModel* self) {
24226fa459cSmrg  return self->min_cost_cmd_;
24326fa459cSmrg}
24426fa459cSmrg
24526fa459cSmrg/* REQUIRES: len >= 2, start_pos <= pos */
24626fa459cSmrg/* REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity */
24726fa459cSmrg/* Maintains the "ZopfliNode array invariant". */
24826fa459cSmrgstatic BROTLI_INLINE void UpdateZopfliNode(ZopfliNode* nodes, size_t pos,
24926fa459cSmrg    size_t start_pos, size_t len, size_t len_code, size_t dist,
25026fa459cSmrg    size_t short_code, float cost) {
25126fa459cSmrg  ZopfliNode* next = &nodes[pos + len];
25226fa459cSmrg  next->length = (uint32_t)(len | ((len + 9u - len_code) << 25));
25326fa459cSmrg  next->distance = (uint32_t)dist;
25426fa459cSmrg  next->dcode_insert_length = (uint32_t)(
25526fa459cSmrg      (short_code << 27) | (pos - start_pos));
25626fa459cSmrg  next->u.cost = cost;
25726fa459cSmrg}
25826fa459cSmrg
25926fa459cSmrgtypedef struct PosData {
26026fa459cSmrg  size_t pos;
26126fa459cSmrg  int distance_cache[4];
26226fa459cSmrg  float costdiff;
26326fa459cSmrg  float cost;
26426fa459cSmrg} PosData;
26526fa459cSmrg
26626fa459cSmrg/* Maintains the smallest 8 cost difference together with their positions */
26726fa459cSmrgtypedef struct StartPosQueue {
26826fa459cSmrg  PosData q_[8];
26926fa459cSmrg  size_t idx_;
27026fa459cSmrg} StartPosQueue;
27126fa459cSmrg
27226fa459cSmrgstatic BROTLI_INLINE void InitStartPosQueue(StartPosQueue* self) {
27326fa459cSmrg  self->idx_ = 0;
27426fa459cSmrg}
27526fa459cSmrg
27626fa459cSmrgstatic size_t StartPosQueueSize(const StartPosQueue* self) {
27726fa459cSmrg  return BROTLI_MIN(size_t, self->idx_, 8);
27826fa459cSmrg}
27926fa459cSmrg
28026fa459cSmrgstatic void StartPosQueuePush(StartPosQueue* self, const PosData* posdata) {
28126fa459cSmrg  size_t offset = ~(self->idx_++) & 7;
28226fa459cSmrg  size_t len = StartPosQueueSize(self);
28326fa459cSmrg  size_t i;
28426fa459cSmrg  PosData* q = self->q_;
28526fa459cSmrg  q[offset] = *posdata;
28626fa459cSmrg  /* Restore the sorted order. In the list of |len| items at most |len - 1|
28726fa459cSmrg     adjacent element comparisons / swaps are required. */
28826fa459cSmrg  for (i = 1; i < len; ++i) {
28926fa459cSmrg    if (q[offset & 7].costdiff > q[(offset + 1) & 7].costdiff) {
29026fa459cSmrg      BROTLI_SWAP(PosData, q, offset & 7, (offset + 1) & 7);
29126fa459cSmrg    }
29226fa459cSmrg    ++offset;
29326fa459cSmrg  }
29426fa459cSmrg}
29526fa459cSmrg
29626fa459cSmrgstatic const PosData* StartPosQueueAt(const StartPosQueue* self, size_t k) {
29726fa459cSmrg  return &self->q_[(k - self->idx_) & 7];
29826fa459cSmrg}
29926fa459cSmrg
30026fa459cSmrg/* Returns the minimum possible copy length that can improve the cost of any */
30126fa459cSmrg/* future position. */
30226fa459cSmrgstatic size_t ComputeMinimumCopyLength(const float start_cost,
30326fa459cSmrg                                       const ZopfliNode* nodes,
30426fa459cSmrg                                       const size_t num_bytes,
30526fa459cSmrg                                       const size_t pos) {
30626fa459cSmrg  /* Compute the minimum possible cost of reaching any future position. */
30726fa459cSmrg  float min_cost = start_cost;
30826fa459cSmrg  size_t len = 2;
30926fa459cSmrg  size_t next_len_bucket = 4;
31026fa459cSmrg  size_t next_len_offset = 10;
31126fa459cSmrg  while (pos + len <= num_bytes && nodes[pos + len].u.cost <= min_cost) {
31226fa459cSmrg    /* We already reached (pos + len) with no more cost than the minimum
31326fa459cSmrg       possible cost of reaching anything from this pos, so there is no point in
31426fa459cSmrg       looking for lengths <= len. */
31526fa459cSmrg    ++len;
31626fa459cSmrg    if (len == next_len_offset) {
31726fa459cSmrg      /* We reached the next copy length code bucket, so we add one more
31826fa459cSmrg         extra bit to the minimum cost. */
31926fa459cSmrg      min_cost += 1.0f;
32026fa459cSmrg      next_len_offset += next_len_bucket;
32126fa459cSmrg      next_len_bucket *= 2;
32226fa459cSmrg    }
32326fa459cSmrg  }
32426fa459cSmrg  return len;
32526fa459cSmrg}
32626fa459cSmrg
32726fa459cSmrg/* REQUIRES: nodes[pos].cost < kInfinity
32826fa459cSmrg   REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
32926fa459cSmrgstatic uint32_t ComputeDistanceShortcut(const size_t block_start,
33026fa459cSmrg                                        const size_t pos,
33126fa459cSmrg                                        const size_t max_backward_limit,
33226fa459cSmrg                                        const size_t gap,
33326fa459cSmrg                                        const ZopfliNode* nodes) {
33426fa459cSmrg  const size_t clen = ZopfliNodeCopyLength(&nodes[pos]);
33526fa459cSmrg  const size_t ilen = nodes[pos].dcode_insert_length & 0x7FFFFFF;
33626fa459cSmrg  const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]);
33726fa459cSmrg  /* Since |block_start + pos| is the end position of the command, the copy part
33826fa459cSmrg     starts from |block_start + pos - clen|. Distances that are greater than
33926fa459cSmrg     this or greater than |max_backward_limit| + |gap| are static dictionary
34026fa459cSmrg     references, and do not update the last distances.
34126fa459cSmrg     Also distance code 0 (last distance) does not update the last distances. */
34226fa459cSmrg  if (pos == 0) {
34326fa459cSmrg    return 0;
34426fa459cSmrg  } else if (dist + clen <= block_start + pos + gap &&
34526fa459cSmrg             dist <= max_backward_limit + gap &&
34626fa459cSmrg             ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
34726fa459cSmrg    return (uint32_t)pos;
34826fa459cSmrg  } else {
34926fa459cSmrg    return nodes[pos - clen - ilen].u.shortcut;
35026fa459cSmrg  }
35126fa459cSmrg}
35226fa459cSmrg
35326fa459cSmrg/* Fills in dist_cache[0..3] with the last four distances (as defined by
35426fa459cSmrg   Section 4. of the Spec) that would be used at (block_start + pos) if we
35526fa459cSmrg   used the shortest path of commands from block_start, computed from
35626fa459cSmrg   nodes[0..pos]. The last four distances at block_start are in
35726fa459cSmrg   starting_dist_cache[0..3].
35826fa459cSmrg   REQUIRES: nodes[pos].cost < kInfinity
35926fa459cSmrg   REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
36026fa459cSmrgstatic void ComputeDistanceCache(const size_t pos,
36126fa459cSmrg                                 const int* starting_dist_cache,
36226fa459cSmrg                                 const ZopfliNode* nodes,
36326fa459cSmrg                                 int* dist_cache) {
36426fa459cSmrg  int idx = 0;
36526fa459cSmrg  size_t p = nodes[pos].u.shortcut;
36626fa459cSmrg  while (idx < 4 && p > 0) {
36726fa459cSmrg    const size_t ilen = nodes[p].dcode_insert_length & 0x7FFFFFF;
36826fa459cSmrg    const size_t clen = ZopfliNodeCopyLength(&nodes[p]);
36926fa459cSmrg    const size_t dist = ZopfliNodeCopyDistance(&nodes[p]);
37026fa459cSmrg    dist_cache[idx++] = (int)dist;
37126fa459cSmrg    /* Because of prerequisite, p >= clen + ilen >= 2. */
37226fa459cSmrg    p = nodes[p - clen - ilen].u.shortcut;
37326fa459cSmrg  }
37426fa459cSmrg  for (; idx < 4; ++idx) {
37526fa459cSmrg    dist_cache[idx] = *starting_dist_cache++;
37626fa459cSmrg  }
37726fa459cSmrg}
37826fa459cSmrg
37926fa459cSmrg/* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it
38026fa459cSmrg   is eligible. */
38126fa459cSmrgstatic void EvaluateNode(
38226fa459cSmrg    const size_t block_start, const size_t pos, const size_t max_backward_limit,
38326fa459cSmrg    const size_t gap, const int* starting_dist_cache,
38426fa459cSmrg    const ZopfliCostModel* model, StartPosQueue* queue, ZopfliNode* nodes) {
38526fa459cSmrg  /* Save cost, because ComputeDistanceCache invalidates it. */
38626fa459cSmrg  float node_cost = nodes[pos].u.cost;
38726fa459cSmrg  nodes[pos].u.shortcut = ComputeDistanceShortcut(
38826fa459cSmrg      block_start, pos, max_backward_limit, gap, nodes);
38926fa459cSmrg  if (node_cost <= ZopfliCostModelGetLiteralCosts(model, 0, pos)) {
39026fa459cSmrg    PosData posdata;
39126fa459cSmrg    posdata.pos = pos;
39226fa459cSmrg    posdata.cost = node_cost;
39326fa459cSmrg    posdata.costdiff = node_cost -
39426fa459cSmrg        ZopfliCostModelGetLiteralCosts(model, 0, pos);
39526fa459cSmrg    ComputeDistanceCache(
39626fa459cSmrg        pos, starting_dist_cache, nodes, posdata.distance_cache);
39726fa459cSmrg    StartPosQueuePush(queue, &posdata);
39826fa459cSmrg  }
39926fa459cSmrg}
40026fa459cSmrg
40126fa459cSmrg/* Returns longest copy length. */
40226fa459cSmrgstatic size_t UpdateNodes(
40326fa459cSmrg    const size_t num_bytes, const size_t block_start, const size_t pos,
40426fa459cSmrg    const uint8_t* ringbuffer, const size_t ringbuffer_mask,
40526fa459cSmrg    const BrotliEncoderParams* params, const size_t max_backward_limit,
40626fa459cSmrg    const int* starting_dist_cache, const size_t num_matches,
40726fa459cSmrg    const BackwardMatch* matches, const ZopfliCostModel* model,
40826fa459cSmrg    StartPosQueue* queue, ZopfliNode* nodes) {
40926fa459cSmrg  const size_t stream_offset = params->stream_offset;
41026fa459cSmrg  const size_t cur_ix = block_start + pos;
41126fa459cSmrg  const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
41226fa459cSmrg  const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
41326fa459cSmrg  const size_t dictionary_start = BROTLI_MIN(size_t,
41426fa459cSmrg      cur_ix + stream_offset, max_backward_limit);
41526fa459cSmrg  const size_t max_len = num_bytes - pos;
41626fa459cSmrg  const size_t max_zopfli_len = MaxZopfliLen(params);
41726fa459cSmrg  const size_t max_iters = MaxZopfliCandidates(params);
41826fa459cSmrg  size_t min_len;
41926fa459cSmrg  size_t result = 0;
42026fa459cSmrg  size_t k;
42126fa459cSmrg  size_t gap = 0;
42226fa459cSmrg
42326fa459cSmrg  EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
42426fa459cSmrg      starting_dist_cache, model, queue, nodes);
42526fa459cSmrg
42626fa459cSmrg  {
42726fa459cSmrg    const PosData* posdata = StartPosQueueAt(queue, 0);
42826fa459cSmrg    float min_cost = (posdata->cost + ZopfliCostModelGetMinCostCmd(model) +
42926fa459cSmrg        ZopfliCostModelGetLiteralCosts(model, posdata->pos, pos));
43026fa459cSmrg    min_len = ComputeMinimumCopyLength(min_cost, nodes, num_bytes, pos);
43126fa459cSmrg  }
43226fa459cSmrg
43326fa459cSmrg  /* Go over the command starting positions in order of increasing cost
43426fa459cSmrg     difference. */
43526fa459cSmrg  for (k = 0; k < max_iters && k < StartPosQueueSize(queue); ++k) {
43626fa459cSmrg    const PosData* posdata = StartPosQueueAt(queue, k);
43726fa459cSmrg    const size_t start = posdata->pos;
43826fa459cSmrg    const uint16_t inscode = GetInsertLengthCode(pos - start);
43926fa459cSmrg    const float start_costdiff = posdata->costdiff;
44026fa459cSmrg    const float base_cost = start_costdiff + (float)GetInsertExtra(inscode) +
44126fa459cSmrg        ZopfliCostModelGetLiteralCosts(model, 0, pos);
44226fa459cSmrg
44326fa459cSmrg    /* Look for last distance matches using the distance cache from this
44426fa459cSmrg       starting position. */
44526fa459cSmrg    size_t best_len = min_len - 1;
44626fa459cSmrg    size_t j = 0;
44726fa459cSmrg    for (; j < BROTLI_NUM_DISTANCE_SHORT_CODES && best_len < max_len; ++j) {
44826fa459cSmrg      const size_t idx = kDistanceCacheIndex[j];
44926fa459cSmrg      const size_t backward =
45026fa459cSmrg          (size_t)(posdata->distance_cache[idx] + kDistanceCacheOffset[j]);
45126fa459cSmrg      size_t prev_ix = cur_ix - backward;
45226fa459cSmrg      size_t len = 0;
45326fa459cSmrg      uint8_t continuation = ringbuffer[cur_ix_masked + best_len];
45426fa459cSmrg      if (cur_ix_masked + best_len > ringbuffer_mask) {
45526fa459cSmrg        break;
45626fa459cSmrg      }
45726fa459cSmrg      if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
45826fa459cSmrg        /* Word dictionary -> ignore. */
45926fa459cSmrg        continue;
46026fa459cSmrg      }
46126fa459cSmrg      if (backward <= max_distance) {
46226fa459cSmrg        /* Regular backward reference. */
46326fa459cSmrg        if (prev_ix >= cur_ix) {
46426fa459cSmrg          continue;
46526fa459cSmrg        }
46626fa459cSmrg
46726fa459cSmrg        prev_ix &= ringbuffer_mask;
46826fa459cSmrg        if (prev_ix + best_len > ringbuffer_mask ||
46926fa459cSmrg            continuation != ringbuffer[prev_ix + best_len]) {
47026fa459cSmrg          continue;
47126fa459cSmrg        }
47226fa459cSmrg        len = FindMatchLengthWithLimit(&ringbuffer[prev_ix],
47326fa459cSmrg                                       &ringbuffer[cur_ix_masked],
47426fa459cSmrg                                       max_len);
47526fa459cSmrg      } else {
47626fa459cSmrg        /* "Gray" area. It is addressable by decoder, but this encoder
47726fa459cSmrg           instance does not have that data -> should not touch it. */
47826fa459cSmrg        continue;
47926fa459cSmrg      }
48026fa459cSmrg      {
48126fa459cSmrg        const float dist_cost = base_cost +
48226fa459cSmrg            ZopfliCostModelGetDistanceCost(model, j);
48326fa459cSmrg        size_t l;
48426fa459cSmrg        for (l = best_len + 1; l <= len; ++l) {
48526fa459cSmrg          const uint16_t copycode = GetCopyLengthCode(l);
48626fa459cSmrg          const uint16_t cmdcode =
48726fa459cSmrg              CombineLengthCodes(inscode, copycode, j == 0);
48826fa459cSmrg          const float cost = (cmdcode < 128 ? base_cost : dist_cost) +
48926fa459cSmrg              (float)GetCopyExtra(copycode) +
49026fa459cSmrg              ZopfliCostModelGetCommandCost(model, cmdcode);
49126fa459cSmrg          if (cost < nodes[pos + l].u.cost) {
49226fa459cSmrg            UpdateZopfliNode(nodes, pos, start, l, l, backward, j + 1, cost);
49326fa459cSmrg            result = BROTLI_MAX(size_t, result, l);
49426fa459cSmrg          }
49526fa459cSmrg          best_len = l;
49626fa459cSmrg        }
49726fa459cSmrg      }
49826fa459cSmrg    }
49926fa459cSmrg
50026fa459cSmrg    /* At higher iterations look only for new last distance matches, since
50126fa459cSmrg       looking only for new command start positions with the same distances
50226fa459cSmrg       does not help much. */
50326fa459cSmrg    if (k >= 2) continue;
50426fa459cSmrg
50526fa459cSmrg    {
50626fa459cSmrg      /* Loop through all possible copy lengths at this position. */
50726fa459cSmrg      size_t len = min_len;
50826fa459cSmrg      for (j = 0; j < num_matches; ++j) {
50926fa459cSmrg        BackwardMatch match = matches[j];
51026fa459cSmrg        size_t dist = match.distance;
51126fa459cSmrg        BROTLI_BOOL is_dictionary_match =
51226fa459cSmrg            TO_BROTLI_BOOL(dist > dictionary_start + gap);
51326fa459cSmrg        /* We already tried all possible last distance matches, so we can use
51426fa459cSmrg           normal distance code here. */
51526fa459cSmrg        size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
51626fa459cSmrg        uint16_t dist_symbol;
51726fa459cSmrg        uint32_t distextra;
51826fa459cSmrg        uint32_t distnumextra;
51926fa459cSmrg        float dist_cost;
52026fa459cSmrg        size_t max_match_len;
52126fa459cSmrg        PrefixEncodeCopyDistance(
52226fa459cSmrg            dist_code, params->dist.num_direct_distance_codes,
52326fa459cSmrg            params->dist.distance_postfix_bits, &dist_symbol, &distextra);
52426fa459cSmrg        distnumextra = dist_symbol >> 10;
52526fa459cSmrg        dist_cost = base_cost + (float)distnumextra +
52626fa459cSmrg            ZopfliCostModelGetDistanceCost(model, dist_symbol & 0x3FF);
52726fa459cSmrg
52826fa459cSmrg        /* Try all copy lengths up until the maximum copy length corresponding
52926fa459cSmrg           to this distance. If the distance refers to the static dictionary, or
53026fa459cSmrg           the maximum length is long enough, try only one maximum length. */
53126fa459cSmrg        max_match_len = BackwardMatchLength(&match);
53226fa459cSmrg        if (len < max_match_len &&
53326fa459cSmrg            (is_dictionary_match || max_match_len > max_zopfli_len)) {
53426fa459cSmrg          len = max_match_len;
53526fa459cSmrg        }
53626fa459cSmrg        for (; len <= max_match_len; ++len) {
53726fa459cSmrg          const size_t len_code =
53826fa459cSmrg              is_dictionary_match ? BackwardMatchLengthCode(&match) : len;
53926fa459cSmrg          const uint16_t copycode = GetCopyLengthCode(len_code);
54026fa459cSmrg          const uint16_t cmdcode = CombineLengthCodes(inscode, copycode, 0);
54126fa459cSmrg          const float cost = dist_cost + (float)GetCopyExtra(copycode) +
54226fa459cSmrg              ZopfliCostModelGetCommandCost(model, cmdcode);
54326fa459cSmrg          if (cost < nodes[pos + len].u.cost) {
54426fa459cSmrg            UpdateZopfliNode(nodes, pos, start, len, len_code, dist, 0, cost);
54526fa459cSmrg            result = BROTLI_MAX(size_t, result, len);
54626fa459cSmrg          }
54726fa459cSmrg        }
54826fa459cSmrg      }
54926fa459cSmrg    }
55026fa459cSmrg  }
55126fa459cSmrg  return result;
55226fa459cSmrg}
55326fa459cSmrg
55426fa459cSmrgstatic size_t ComputeShortestPathFromNodes(size_t num_bytes,
55526fa459cSmrg    ZopfliNode* nodes) {
55626fa459cSmrg  size_t index = num_bytes;
55726fa459cSmrg  size_t num_commands = 0;
55826fa459cSmrg  while ((nodes[index].dcode_insert_length & 0x7FFFFFF) == 0 &&
55926fa459cSmrg      nodes[index].length == 1) --index;
56026fa459cSmrg  nodes[index].u.next = BROTLI_UINT32_MAX;
56126fa459cSmrg  while (index != 0) {
56226fa459cSmrg    size_t len = ZopfliNodeCommandLength(&nodes[index]);
56326fa459cSmrg    index -= len;
56426fa459cSmrg    nodes[index].u.next = (uint32_t)len;
56526fa459cSmrg    num_commands++;
56626fa459cSmrg  }
56726fa459cSmrg  return num_commands;
56826fa459cSmrg}
56926fa459cSmrg
57026fa459cSmrg/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
57126fa459cSmrgvoid BrotliZopfliCreateCommands(const size_t num_bytes,
57226fa459cSmrg    const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
57326fa459cSmrg    size_t* last_insert_len, const BrotliEncoderParams* params,
57426fa459cSmrg    Command* commands, size_t* num_literals) {
57526fa459cSmrg  const size_t stream_offset = params->stream_offset;
57626fa459cSmrg  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
57726fa459cSmrg  size_t pos = 0;
57826fa459cSmrg  uint32_t offset = nodes[0].u.next;
57926fa459cSmrg  size_t i;
58026fa459cSmrg  size_t gap = 0;
58126fa459cSmrg  for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
58226fa459cSmrg    const ZopfliNode* next = &nodes[pos + offset];
58326fa459cSmrg    size_t copy_length = ZopfliNodeCopyLength(next);
58426fa459cSmrg    size_t insert_length = next->dcode_insert_length & 0x7FFFFFF;
58526fa459cSmrg    pos += insert_length;
58626fa459cSmrg    offset = next->u.next;
58726fa459cSmrg    if (i == 0) {
58826fa459cSmrg      insert_length += *last_insert_len;
58926fa459cSmrg      *last_insert_len = 0;
59026fa459cSmrg    }
59126fa459cSmrg    {
59226fa459cSmrg      size_t distance = ZopfliNodeCopyDistance(next);
59326fa459cSmrg      size_t len_code = ZopfliNodeLengthCode(next);
59426fa459cSmrg      size_t dictionary_start = BROTLI_MIN(size_t,
59526fa459cSmrg          block_start + pos + stream_offset, max_backward_limit);
59626fa459cSmrg      BROTLI_BOOL is_dictionary =
59726fa459cSmrg          TO_BROTLI_BOOL(distance > dictionary_start + gap);
59826fa459cSmrg      size_t dist_code = ZopfliNodeDistanceCode(next);
59926fa459cSmrg      InitCommand(&commands[i], &params->dist, insert_length,
60026fa459cSmrg          copy_length, (int)len_code - (int)copy_length, dist_code);
60126fa459cSmrg
60226fa459cSmrg      if (!is_dictionary && dist_code > 0) {
60326fa459cSmrg        dist_cache[3] = dist_cache[2];
60426fa459cSmrg        dist_cache[2] = dist_cache[1];
60526fa459cSmrg        dist_cache[1] = dist_cache[0];
60626fa459cSmrg        dist_cache[0] = (int)distance;
60726fa459cSmrg      }
60826fa459cSmrg    }
60926fa459cSmrg
61026fa459cSmrg    *num_literals += insert_length;
61126fa459cSmrg    pos += copy_length;
61226fa459cSmrg  }
61326fa459cSmrg  *last_insert_len += num_bytes - pos;
61426fa459cSmrg}
61526fa459cSmrg
61626fa459cSmrgstatic size_t ZopfliIterate(size_t num_bytes, size_t position,
61726fa459cSmrg    const uint8_t* ringbuffer, size_t ringbuffer_mask,
61826fa459cSmrg    const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
61926fa459cSmrg    const ZopfliCostModel* model, const uint32_t* num_matches,
62026fa459cSmrg    const BackwardMatch* matches, ZopfliNode* nodes) {
62126fa459cSmrg  const size_t stream_offset = params->stream_offset;
62226fa459cSmrg  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
62326fa459cSmrg  const size_t max_zopfli_len = MaxZopfliLen(params);
62426fa459cSmrg  StartPosQueue queue;
62526fa459cSmrg  size_t cur_match_pos = 0;
62626fa459cSmrg  size_t i;
62726fa459cSmrg  nodes[0].length = 0;
62826fa459cSmrg  nodes[0].u.cost = 0;
62926fa459cSmrg  InitStartPosQueue(&queue);
63026fa459cSmrg  for (i = 0; i + 3 < num_bytes; i++) {
63126fa459cSmrg    size_t skip = UpdateNodes(num_bytes, position, i, ringbuffer,
63226fa459cSmrg        ringbuffer_mask, params, max_backward_limit, dist_cache,
63326fa459cSmrg        num_matches[i], &matches[cur_match_pos], model, &queue, nodes);
63426fa459cSmrg    if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
63526fa459cSmrg    cur_match_pos += num_matches[i];
63626fa459cSmrg    if (num_matches[i] == 1 &&
63726fa459cSmrg        BackwardMatchLength(&matches[cur_match_pos - 1]) > max_zopfli_len) {
63826fa459cSmrg      skip = BROTLI_MAX(size_t,
63926fa459cSmrg          BackwardMatchLength(&matches[cur_match_pos - 1]), skip);
64026fa459cSmrg    }
64126fa459cSmrg    if (skip > 1) {
64226fa459cSmrg      skip--;
64326fa459cSmrg      while (skip) {
64426fa459cSmrg        i++;
64526fa459cSmrg        if (i + 3 >= num_bytes) break;
64626fa459cSmrg        EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
64726fa459cSmrg            dist_cache, model, &queue, nodes);
64826fa459cSmrg        cur_match_pos += num_matches[i];
64926fa459cSmrg        skip--;
65026fa459cSmrg      }
65126fa459cSmrg    }
65226fa459cSmrg  }
65326fa459cSmrg  return ComputeShortestPathFromNodes(num_bytes, nodes);
65426fa459cSmrg}
65526fa459cSmrg
65626fa459cSmrg/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
65726fa459cSmrgsize_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
65826fa459cSmrg    size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
65926fa459cSmrg    ContextLut literal_context_lut, const BrotliEncoderParams* params,
66026fa459cSmrg    const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) {
66126fa459cSmrg  const size_t stream_offset = params->stream_offset;
66226fa459cSmrg  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
66326fa459cSmrg  const size_t max_zopfli_len = MaxZopfliLen(params);
66426fa459cSmrg  ZopfliCostModel model;
66526fa459cSmrg  StartPosQueue queue;
66626fa459cSmrg  BackwardMatch matches[2 * (MAX_NUM_MATCHES_H10 + 64)];
66726fa459cSmrg  const size_t store_end = num_bytes >= StoreLookaheadH10() ?
66826fa459cSmrg      position + num_bytes - StoreLookaheadH10() + 1 : position;
66926fa459cSmrg  size_t i;
67026fa459cSmrg  size_t gap = 0;
67126fa459cSmrg  size_t lz_matches_offset = 0;
67226fa459cSmrg  BROTLI_UNUSED(literal_context_lut);
67326fa459cSmrg  nodes[0].length = 0;
67426fa459cSmrg  nodes[0].u.cost = 0;
67526fa459cSmrg  InitZopfliCostModel(m, &model, &params->dist, num_bytes);
67626fa459cSmrg  if (BROTLI_IS_OOM(m)) return 0;
67726fa459cSmrg  ZopfliCostModelSetFromLiteralCosts(
67826fa459cSmrg      &model, position, ringbuffer, ringbuffer_mask);
67926fa459cSmrg  InitStartPosQueue(&queue);
68026fa459cSmrg  for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
68126fa459cSmrg    const size_t pos = position + i;
68226fa459cSmrg    const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
68326fa459cSmrg    const size_t dictionary_start = BROTLI_MIN(size_t,
68426fa459cSmrg        pos + stream_offset, max_backward_limit);
68526fa459cSmrg    size_t skip;
68626fa459cSmrg    size_t num_matches;
68726fa459cSmrg    num_matches = FindAllMatchesH10(&hasher->privat._H10,
68826fa459cSmrg        &params->dictionary,
68926fa459cSmrg        ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
69026fa459cSmrg        dictionary_start + gap, params, &matches[lz_matches_offset]);
69126fa459cSmrg    if (num_matches > 0 &&
69226fa459cSmrg        BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
69326fa459cSmrg      matches[0] = matches[num_matches - 1];
69426fa459cSmrg      num_matches = 1;
69526fa459cSmrg    }
69626fa459cSmrg    skip = UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask,
69726fa459cSmrg        params, max_backward_limit, dist_cache, num_matches, matches, &model,
69826fa459cSmrg        &queue, nodes);
69926fa459cSmrg    if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
70026fa459cSmrg    if (num_matches == 1 && BackwardMatchLength(&matches[0]) > max_zopfli_len) {
70126fa459cSmrg      skip = BROTLI_MAX(size_t, BackwardMatchLength(&matches[0]), skip);
70226fa459cSmrg    }
70326fa459cSmrg    if (skip > 1) {
70426fa459cSmrg      /* Add the tail of the copy to the hasher. */
70526fa459cSmrg      StoreRangeH10(&hasher->privat._H10,
70626fa459cSmrg          ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
70726fa459cSmrg          size_t, pos + skip, store_end));
70826fa459cSmrg      skip--;
70926fa459cSmrg      while (skip) {
71026fa459cSmrg        i++;
71126fa459cSmrg        if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
71226fa459cSmrg        EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
71326fa459cSmrg            dist_cache, &model, &queue, nodes);
71426fa459cSmrg        skip--;
71526fa459cSmrg      }
71626fa459cSmrg    }
71726fa459cSmrg  }
71826fa459cSmrg  CleanupZopfliCostModel(m, &model);
71926fa459cSmrg  return ComputeShortestPathFromNodes(num_bytes, nodes);
72026fa459cSmrg}
72126fa459cSmrg
72226fa459cSmrgvoid BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
72326fa459cSmrg    size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
72426fa459cSmrg    ContextLut literal_context_lut, const BrotliEncoderParams* params,
72526fa459cSmrg    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
72626fa459cSmrg    Command* commands, size_t* num_commands, size_t* num_literals) {
72726fa459cSmrg  ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
72826fa459cSmrg  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
72926fa459cSmrg  BrotliInitZopfliNodes(nodes, num_bytes + 1);
73026fa459cSmrg  *num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
73126fa459cSmrg      position, ringbuffer, ringbuffer_mask, literal_context_lut, params,
73226fa459cSmrg      dist_cache, hasher, nodes);
73326fa459cSmrg  if (BROTLI_IS_OOM(m)) return;
73426fa459cSmrg  BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
73526fa459cSmrg      last_insert_len, params, commands, num_literals);
73626fa459cSmrg  BROTLI_FREE(m, nodes);
73726fa459cSmrg}
73826fa459cSmrg
73926fa459cSmrgvoid BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
74026fa459cSmrg    size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
74126fa459cSmrg    ContextLut literal_context_lut, const BrotliEncoderParams* params,
74226fa459cSmrg    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
74326fa459cSmrg    Command* commands, size_t* num_commands, size_t* num_literals) {
74426fa459cSmrg  const size_t stream_offset = params->stream_offset;
74526fa459cSmrg  const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
74626fa459cSmrg  uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
74726fa459cSmrg  size_t matches_size = 4 * num_bytes;
74826fa459cSmrg  const size_t store_end = num_bytes >= StoreLookaheadH10() ?
74926fa459cSmrg      position + num_bytes - StoreLookaheadH10() + 1 : position;
75026fa459cSmrg  size_t cur_match_pos = 0;
75126fa459cSmrg  size_t i;
75226fa459cSmrg  size_t orig_num_literals;
75326fa459cSmrg  size_t orig_last_insert_len;
75426fa459cSmrg  int orig_dist_cache[4];
75526fa459cSmrg  size_t orig_num_commands;
75626fa459cSmrg  ZopfliCostModel model;
75726fa459cSmrg  ZopfliNode* nodes;
75826fa459cSmrg  BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
75926fa459cSmrg  size_t gap = 0;
76026fa459cSmrg  size_t shadow_matches = 0;
76126fa459cSmrg  BROTLI_UNUSED(literal_context_lut);
76226fa459cSmrg  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(num_matches) ||
76326fa459cSmrg      BROTLI_IS_NULL(matches)) {
76426fa459cSmrg    return;
76526fa459cSmrg  }
76626fa459cSmrg  for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
76726fa459cSmrg    const size_t pos = position + i;
76826fa459cSmrg    size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
76926fa459cSmrg    size_t dictionary_start = BROTLI_MIN(size_t,
77026fa459cSmrg        pos + stream_offset, max_backward_limit);
77126fa459cSmrg    size_t max_length = num_bytes - i;
77226fa459cSmrg    size_t num_found_matches;
77326fa459cSmrg    size_t cur_match_end;
77426fa459cSmrg    size_t j;
77526fa459cSmrg    /* Ensure that we have enough free slots. */
77626fa459cSmrg    BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
77726fa459cSmrg        cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
77826fa459cSmrg    if (BROTLI_IS_OOM(m)) return;
77926fa459cSmrg    num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
78026fa459cSmrg        &params->dictionary,
78126fa459cSmrg        ringbuffer, ringbuffer_mask, pos, max_length,
78226fa459cSmrg        max_distance, dictionary_start + gap, params,
78326fa459cSmrg        &matches[cur_match_pos + shadow_matches]);
78426fa459cSmrg    cur_match_end = cur_match_pos + num_found_matches;
78526fa459cSmrg    for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
78626fa459cSmrg      BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <=
78726fa459cSmrg          BackwardMatchLength(&matches[j + 1]));
78826fa459cSmrg    }
78926fa459cSmrg    num_matches[i] = (uint32_t)num_found_matches;
79026fa459cSmrg    if (num_found_matches > 0) {
79126fa459cSmrg      const size_t match_len = BackwardMatchLength(&matches[cur_match_end - 1]);
79226fa459cSmrg      if (match_len > MAX_ZOPFLI_LEN_QUALITY_11) {
79326fa459cSmrg        const size_t skip = match_len - 1;
79426fa459cSmrg        matches[cur_match_pos++] = matches[cur_match_end - 1];
79526fa459cSmrg        num_matches[i] = 1;
79626fa459cSmrg        /* Add the tail of the copy to the hasher. */
79726fa459cSmrg        StoreRangeH10(&hasher->privat._H10,
79826fa459cSmrg                      ringbuffer, ringbuffer_mask, pos + 1,
79926fa459cSmrg                      BROTLI_MIN(size_t, pos + match_len, store_end));
80026fa459cSmrg        memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
80126fa459cSmrg        i += skip;
80226fa459cSmrg      } else {
80326fa459cSmrg        cur_match_pos = cur_match_end;
80426fa459cSmrg      }
80526fa459cSmrg    }
80626fa459cSmrg  }
80726fa459cSmrg  orig_num_literals = *num_literals;
80826fa459cSmrg  orig_last_insert_len = *last_insert_len;
80926fa459cSmrg  memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
81026fa459cSmrg  orig_num_commands = *num_commands;
81126fa459cSmrg  nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
81226fa459cSmrg  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
81326fa459cSmrg  InitZopfliCostModel(m, &model, &params->dist, num_bytes);
81426fa459cSmrg  if (BROTLI_IS_OOM(m)) return;
81526fa459cSmrg  for (i = 0; i < 2; i++) {
81626fa459cSmrg    BrotliInitZopfliNodes(nodes, num_bytes + 1);
81726fa459cSmrg    if (i == 0) {
81826fa459cSmrg      ZopfliCostModelSetFromLiteralCosts(
81926fa459cSmrg          &model, position, ringbuffer, ringbuffer_mask);
82026fa459cSmrg    } else {
82126fa459cSmrg      ZopfliCostModelSetFromCommands(&model, position, ringbuffer,
82226fa459cSmrg          ringbuffer_mask, commands, *num_commands - orig_num_commands,
82326fa459cSmrg          orig_last_insert_len);
82426fa459cSmrg    }
82526fa459cSmrg    *num_commands = orig_num_commands;
82626fa459cSmrg    *num_literals = orig_num_literals;
82726fa459cSmrg    *last_insert_len = orig_last_insert_len;
82826fa459cSmrg    memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
82926fa459cSmrg    *num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
83026fa459cSmrg        ringbuffer_mask, params, gap, dist_cache, &model, num_matches, matches,
83126fa459cSmrg        nodes);
83226fa459cSmrg    BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
83326fa459cSmrg        last_insert_len, params, commands, num_literals);
83426fa459cSmrg  }
83526fa459cSmrg  CleanupZopfliCostModel(m, &model);
83626fa459cSmrg  BROTLI_FREE(m, nodes);
83726fa459cSmrg  BROTLI_FREE(m, matches);
83826fa459cSmrg  BROTLI_FREE(m, num_matches);
83926fa459cSmrg}
84026fa459cSmrg
84126fa459cSmrg#if defined(__cplusplus) || defined(c_plusplus)
84226fa459cSmrg}  /* extern "C" */
84326fa459cSmrg#endif
844