brotli 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/ext/brotli/brotli.cc +114 -24
  3. data/ext/brotli/brotli.h +0 -1
  4. data/ext/brotli/extconf.rb +30 -23
  5. data/lib/brotli/version.rb +1 -1
  6. data/vendor/brotli/LICENSE +1 -1
  7. data/vendor/brotli/dec/Makefile +1 -1
  8. data/vendor/brotli/dec/bit_reader.c +3 -3
  9. data/vendor/brotli/dec/bit_reader.h +25 -27
  10. data/vendor/brotli/dec/context.h +4 -4
  11. data/vendor/brotli/dec/decode.c +410 -486
  12. data/vendor/brotli/dec/decode.h +101 -105
  13. data/vendor/brotli/dec/dictionary.c +1 -1
  14. data/vendor/brotli/dec/dictionary.h +7 -8
  15. data/vendor/brotli/dec/huffman.c +103 -105
  16. data/vendor/brotli/dec/huffman.h +18 -18
  17. data/vendor/brotli/dec/port.h +52 -40
  18. data/vendor/brotli/dec/prefix.h +2 -0
  19. data/vendor/brotli/dec/state.c +13 -19
  20. data/vendor/brotli/dec/state.h +25 -39
  21. data/vendor/brotli/dec/transform.h +38 -44
  22. data/vendor/brotli/dec/types.h +2 -2
  23. data/vendor/brotli/enc/Makefile +1 -1
  24. data/vendor/brotli/enc/backward_references.cc +455 -359
  25. data/vendor/brotli/enc/backward_references.h +79 -3
  26. data/vendor/brotli/enc/bit_cost.h +54 -32
  27. data/vendor/brotli/enc/block_splitter.cc +285 -193
  28. data/vendor/brotli/enc/block_splitter.h +4 -12
  29. data/vendor/brotli/enc/brotli_bit_stream.cc +623 -324
  30. data/vendor/brotli/enc/brotli_bit_stream.h +76 -37
  31. data/vendor/brotli/enc/cluster.h +161 -120
  32. data/vendor/brotli/enc/command.h +60 -37
  33. data/vendor/brotli/enc/compress_fragment.cc +701 -0
  34. data/vendor/brotli/enc/compress_fragment.h +47 -0
  35. data/vendor/brotli/enc/compress_fragment_two_pass.cc +524 -0
  36. data/vendor/brotli/enc/compress_fragment_two_pass.h +40 -0
  37. data/vendor/brotli/enc/compressor.h +15 -0
  38. data/vendor/brotli/enc/context.h +1 -1
  39. data/vendor/brotli/enc/dictionary.h +2 -2
  40. data/vendor/brotli/enc/encode.cc +819 -286
  41. data/vendor/brotli/enc/encode.h +38 -15
  42. data/vendor/brotli/enc/encode_parallel.cc +40 -42
  43. data/vendor/brotli/enc/entropy_encode.cc +144 -147
  44. data/vendor/brotli/enc/entropy_encode.h +32 -8
  45. data/vendor/brotli/enc/entropy_encode_static.h +572 -0
  46. data/vendor/brotli/enc/fast_log.h +7 -40
  47. data/vendor/brotli/enc/find_match_length.h +9 -9
  48. data/vendor/brotli/enc/hash.h +462 -154
  49. data/vendor/brotli/enc/histogram.cc +6 -6
  50. data/vendor/brotli/enc/histogram.h +13 -13
  51. data/vendor/brotli/enc/literal_cost.cc +45 -45
  52. data/vendor/brotli/enc/metablock.cc +92 -89
  53. data/vendor/brotli/enc/metablock.h +12 -12
  54. data/vendor/brotli/enc/port.h +7 -16
  55. data/vendor/brotli/enc/prefix.h +23 -22
  56. data/vendor/brotli/enc/ringbuffer.h +75 -29
  57. data/vendor/brotli/enc/static_dict.cc +56 -48
  58. data/vendor/brotli/enc/static_dict.h +5 -5
  59. data/vendor/brotli/enc/streams.cc +1 -1
  60. data/vendor/brotli/enc/streams.h +5 -5
  61. data/vendor/brotli/enc/transform.h +40 -35
  62. data/vendor/brotli/enc/types.h +2 -0
  63. data/vendor/brotli/enc/utf8_util.cc +3 -2
  64. data/vendor/brotli/enc/write_bits.h +6 -6
  65. metadata +9 -5
  66. data/vendor/brotli/dec/streams.c +0 -102
  67. data/vendor/brotli/dec/streams.h +0 -95
@@ -18,12 +18,13 @@
18
18
 
19
19
  namespace brotli {
20
20
 
21
- static const double kInfinity = std::numeric_limits<double>::infinity();
21
+ // The maximum length for which the zopflification uses distinct distances.
22
+ static const uint16_t kMaxZopfliLen = 325;
22
23
 
23
24
  // Histogram based cost model for zopflification.
24
25
  class ZopfliCostModel {
25
26
  public:
26
- ZopfliCostModel() : min_cost_cmd_(kInfinity) {}
27
+ ZopfliCostModel(void) : min_cost_cmd_(kInfinity) {}
27
28
 
28
29
  void SetFromCommands(size_t num_bytes,
29
30
  size_t position,
@@ -31,34 +32,34 @@ class ZopfliCostModel {
31
32
  size_t ringbuffer_mask,
32
33
  const Command* commands,
33
34
  size_t num_commands,
34
- int last_insert_len) {
35
- std::vector<int> histogram_literal(256, 0);
36
- std::vector<int> histogram_cmd(kNumCommandPrefixes, 0);
37
- std::vector<int> histogram_dist(kNumDistancePrefixes, 0);
35
+ size_t last_insert_len) {
36
+ std::vector<uint32_t> histogram_literal(256, 0);
37
+ std::vector<uint32_t> histogram_cmd(kNumCommandPrefixes, 0);
38
+ std::vector<uint32_t> histogram_dist(kNumDistancePrefixes, 0);
38
39
 
39
40
  size_t pos = position - last_insert_len;
40
41
  for (size_t i = 0; i < num_commands; i++) {
41
- int inslength = commands[i].insert_len_;
42
- int copylength = commands[i].copy_len_;
43
- int distcode = commands[i].dist_prefix_;
44
- int cmdcode = commands[i].cmd_prefix_;
42
+ size_t inslength = commands[i].insert_len_;
43
+ size_t copylength = commands[i].copy_len();
44
+ size_t distcode = commands[i].dist_prefix_;
45
+ size_t cmdcode = commands[i].cmd_prefix_;
45
46
 
46
47
  histogram_cmd[cmdcode]++;
47
48
  if (cmdcode >= 128) histogram_dist[distcode]++;
48
49
 
49
- for (int j = 0; j < inslength; j++) {
50
+ for (size_t j = 0; j < inslength; j++) {
50
51
  histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
51
52
  }
52
53
 
53
54
  pos += inslength + copylength;
54
55
  }
55
56
 
56
- std::vector<double> cost_literal;
57
+ std::vector<float> cost_literal;
57
58
  Set(histogram_literal, &cost_literal);
58
59
  Set(histogram_cmd, &cost_cmd_);
59
60
  Set(histogram_dist, &cost_dist_);
60
61
 
61
- for (int i = 0; i < kNumCommandPrefixes; ++i) {
62
+ for (uint32_t i = 0; i < kNumCommandPrefixes; ++i) {
62
63
  min_cost_cmd_ = std::min(min_cost_cmd_, cost_cmd_[i]);
63
64
  }
64
65
 
@@ -74,27 +75,26 @@ class ZopfliCostModel {
74
75
  size_t position,
75
76
  const uint8_t* ringbuffer,
76
77
  size_t ringbuffer_mask) {
77
- std::vector<float> literal_cost(num_bytes + 1);
78
+ literal_costs_.resize(num_bytes + 2);
78
79
  EstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask,
79
- ringbuffer, &literal_cost[0]);
80
- literal_costs_.resize(num_bytes + 1);
80
+ ringbuffer, &literal_costs_[1]);
81
81
  literal_costs_[0] = 0.0;
82
82
  for (size_t i = 0; i < num_bytes; ++i) {
83
- literal_costs_[i + 1] = literal_costs_[i] + literal_cost[i];
83
+ literal_costs_[i + 1] += literal_costs_[i];
84
84
  }
85
85
  cost_cmd_.resize(kNumCommandPrefixes);
86
86
  cost_dist_.resize(kNumDistancePrefixes);
87
- for (int i = 0; i < kNumCommandPrefixes; ++i) {
88
- cost_cmd_[i] = FastLog2(11 + i);
87
+ for (uint32_t i = 0; i < kNumCommandPrefixes; ++i) {
88
+ cost_cmd_[i] = static_cast<float>(FastLog2(11 + i));
89
89
  }
90
- for (int i = 0; i < kNumDistancePrefixes; ++i) {
91
- cost_dist_[i] = FastLog2(20 + i);
90
+ for (uint32_t i = 0; i < kNumDistancePrefixes; ++i) {
91
+ cost_dist_[i] = static_cast<float>(FastLog2(20 + i));
92
92
  }
93
- min_cost_cmd_ = FastLog2(11);
93
+ min_cost_cmd_ = static_cast<float>(FastLog2(11));
94
94
  }
95
95
 
96
- double GetCommandCost(
97
- int dist_code, int length_code, int insert_length) const {
96
+ float GetCommandCost(
97
+ size_t dist_code, size_t length_code, size_t insert_length) const {
98
98
  uint16_t inscode = GetInsertLengthCode(insert_length);
99
99
  uint16_t copycode = GetCopyLengthCode(length_code);
100
100
  uint16_t cmdcode = CombineLengthCodes(inscode, copycode, dist_code == 0);
@@ -103,28 +103,29 @@ class ZopfliCostModel {
103
103
  PrefixEncodeCopyDistance(dist_code, 0, 0, &dist_symbol, &distextra);
104
104
  uint32_t distnumextra = distextra >> 24;
105
105
 
106
- double result = insextra[inscode] + copyextra[copycode] + distnumextra;
106
+ float result = static_cast<float>(
107
+ GetInsertExtra(inscode) + GetCopyExtra(copycode) + distnumextra);
107
108
  result += cost_cmd_[cmdcode];
108
109
  if (cmdcode >= 128) result += cost_dist_[dist_symbol];
109
110
  return result;
110
111
  }
111
112
 
112
- double GetLiteralCosts(size_t from, size_t to) const {
113
+ float GetLiteralCosts(size_t from, size_t to) const {
113
114
  return literal_costs_[to] - literal_costs_[from];
114
115
  }
115
116
 
116
- double GetMinCostCmd() const {
117
+ float GetMinCostCmd(void) const {
117
118
  return min_cost_cmd_;
118
119
  }
119
120
 
120
121
  private:
121
- void Set(const std::vector<int>& histogram, std::vector<double>* cost) {
122
+ void Set(const std::vector<uint32_t>& histogram, std::vector<float>* cost) {
122
123
  cost->resize(histogram.size());
123
- int sum = 0;
124
+ size_t sum = 0;
124
125
  for (size_t i = 0; i < histogram.size(); i++) {
125
126
  sum += histogram[i];
126
127
  }
127
- double log2sum = FastLog2(sum);
128
+ float log2sum = static_cast<float>(FastLog2(sum));
128
129
  for (size_t i = 0; i < histogram.size(); i++) {
129
130
  if (histogram[i] == 0) {
130
131
  (*cost)[i] = log2sum + 2;
@@ -132,54 +133,42 @@ class ZopfliCostModel {
132
133
  }
133
134
 
134
135
  // Shannon bits for this symbol.
135
- (*cost)[i] = log2sum - FastLog2(histogram[i]);
136
+ (*cost)[i] = log2sum - static_cast<float>(FastLog2(histogram[i]));
136
137
 
137
138
  // Cannot be coded with less than 1 bit
138
139
  if ((*cost)[i] < 1) (*cost)[i] = 1;
139
140
  }
140
141
  }
141
142
 
142
- std::vector<double> cost_cmd_; // The insert and copy length symbols.
143
- std::vector<double> cost_dist_;
143
+ std::vector<float> cost_cmd_; // The insert and copy length symbols.
144
+ std::vector<float> cost_dist_;
144
145
  // Cumulative costs of literals per position in the stream.
145
- std::vector<double> literal_costs_;
146
- double min_cost_cmd_;
146
+ std::vector<float> literal_costs_;
147
+ float min_cost_cmd_;
147
148
  };
148
149
 
149
- inline void SetDistanceCache(int distance,
150
- int distance_code,
151
- int max_distance,
152
- const int* dist_cache,
153
- int* result_dist_cache) {
154
- if (distance <= max_distance && distance_code > 0) {
155
- result_dist_cache[0] = distance;
156
- memcpy(&result_dist_cache[1], dist_cache, 3 * sizeof(dist_cache[0]));
157
- } else {
158
- memcpy(result_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
159
- }
160
- }
161
-
162
- inline int ComputeDistanceCode(int distance,
163
- int max_distance,
164
- int quality,
165
- const int* dist_cache) {
150
+ inline size_t ComputeDistanceCode(size_t distance,
151
+ size_t max_distance,
152
+ int quality,
153
+ const int* dist_cache) {
166
154
  if (distance <= max_distance) {
167
- if (distance == dist_cache[0]) {
155
+ if (distance == static_cast<size_t>(dist_cache[0])) {
168
156
  return 0;
169
- } else if (distance == dist_cache[1]) {
157
+ } else if (distance == static_cast<size_t>(dist_cache[1])) {
170
158
  return 1;
171
- } else if (distance == dist_cache[2]) {
159
+ } else if (distance == static_cast<size_t>(dist_cache[2])) {
172
160
  return 2;
173
- } else if (distance == dist_cache[3]) {
161
+ } else if (distance == static_cast<size_t>(dist_cache[3])) {
174
162
  return 3;
175
163
  } else if (quality > 3 && distance >= 6) {
176
- for (int k = 4; k < kNumDistanceShortCodes; ++k) {
177
- int idx = kDistanceCacheIndex[k];
178
- int candidate = dist_cache[idx] + kDistanceCacheOffset[k];
179
- static const int kLimits[16] = { 0, 0, 0, 0,
180
- 6, 6, 11, 11,
181
- 11, 11, 11, 11,
182
- 12, 12, 12, 12 };
164
+ for (size_t k = 4; k < kNumDistanceShortCodes; ++k) {
165
+ size_t idx = kDistanceCacheIndex[k];
166
+ size_t candidate =
167
+ static_cast<size_t>(dist_cache[idx] + kDistanceCacheOffset[k]);
168
+ static const size_t kLimits[16] = { 0, 0, 0, 0,
169
+ 6, 6, 11, 11,
170
+ 11, 11, 11, 11,
171
+ 12, 12, 12, 12 };
183
172
  if (distance == candidate && distance >= kLimits[k]) {
184
173
  return k;
185
174
  }
@@ -189,99 +178,78 @@ inline int ComputeDistanceCode(int distance,
189
178
  return distance + 15;
190
179
  }
191
180
 
192
- struct ZopfliNode {
193
- ZopfliNode() : length(1),
194
- distance(0),
195
- distance_code(0),
196
- length_code(0),
197
- insert_length(0),
198
- cost(kInfinity) {}
199
-
200
- // best length to get up to this byte (not including this byte itself)
201
- int length;
202
- // distance associated with the length
203
- int distance;
204
- int distance_code;
205
- int distance_cache[4];
206
- // length code associated with the length - usually the same as length,
207
- // except in case of length-changing dictionary transformation.
208
- int length_code;
209
- // number of literal inserts before this copy
210
- int insert_length;
211
- // smallest cost to get to this byte from the beginning, as found so far
212
- double cost;
213
- };
214
-
181
+ // REQUIRES: len >= 2, start_pos <= pos
182
+ // REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity
183
+ // Maintains the "ZopfliNode array invariant".
215
184
  inline void UpdateZopfliNode(ZopfliNode* nodes, size_t pos, size_t start_pos,
216
- int len, int len_code, int dist, int dist_code,
217
- int max_dist, const int* dist_cache,
218
- double cost) {
185
+ size_t len, size_t len_code, size_t dist,
186
+ size_t short_code, float cost) {
219
187
  ZopfliNode& next = nodes[pos + len];
220
- next.length = len;
221
- next.length_code = len_code;
222
- next.distance = dist;
223
- next.distance_code = dist_code;
224
- next.insert_length = static_cast<int>(pos - start_pos);
188
+ next.length = static_cast<uint32_t>(len | ((len + 9u - len_code) << 24));
189
+ next.distance = static_cast<uint32_t>(dist | (short_code << 25));
190
+ next.insert_length = static_cast<uint32_t>(pos - start_pos);
225
191
  next.cost = cost;
226
- SetDistanceCache(dist, dist_code, max_dist, dist_cache,
227
- &next.distance_cache[0]);
228
192
  }
229
193
 
230
194
  // Maintains the smallest 2^k cost difference together with their positions
231
195
  class StartPosQueue {
232
196
  public:
197
+ struct PosData {
198
+ size_t pos;
199
+ int distance_cache[4];
200
+ float costdiff;
201
+ };
202
+
233
203
  explicit StartPosQueue(int bits)
234
- : mask_((1 << bits) - 1), q_(1 << bits), idx_(0) {}
204
+ : mask_((1u << bits) - 1), q_(1 << bits), idx_(0) {}
235
205
 
236
- void Clear() {
206
+ void Clear(void) {
237
207
  idx_ = 0;
238
208
  }
239
209
 
240
- void Push(size_t pos, double costdiff) {
241
- if (costdiff == kInfinity) {
242
- // We can't start a command from an unreachable start position.
243
- // E.g. position 1 in a stream is always unreachable, because all commands
244
- // have a copy of at least length 2.
245
- return;
246
- }
247
- q_[idx_ & mask_] = std::make_pair(pos, costdiff);
248
- // Restore the sorted order.
249
- for (int i = idx_; i > 0 && i > idx_ - mask_; --i) {
250
- if (q_[i & mask_].second > q_[(i - 1) & mask_].second) {
251
- std::swap(q_[i & mask_], q_[(i - 1) & mask_]);
210
+ void Push(const StartPosQueue::PosData& posdata) {
211
+ size_t offset = ~idx_ & mask_;
212
+ ++idx_;
213
+ size_t len = size();
214
+ q_[offset] = posdata;
215
+ /* Restore the sorted order. In the list of |len| items at most |len - 1|
216
+ adjacent element comparisons / swaps are required. */
217
+ for (size_t i = 1; i < len; ++i) {
218
+ if (q_[offset & mask_].costdiff > q_[(offset + 1) & mask_].costdiff) {
219
+ std::swap(q_[offset & mask_], q_[(offset + 1) & mask_]);
252
220
  }
221
+ ++offset;
253
222
  }
254
- ++idx_;
255
223
  }
256
224
 
257
- int size() const { return std::min(idx_, mask_ + 1); }
225
+ size_t size(void) const { return std::min(idx_, mask_ + 1); }
258
226
 
259
- size_t GetStartPos(int k) const {
260
- return q_[(idx_ - k - 1) & mask_].first;
227
+ const StartPosQueue::PosData& GetStartPosData(size_t k) const {
228
+ return q_[(k - idx_) & mask_];
261
229
  }
262
230
 
263
231
  private:
264
- const int mask_;
265
- std::vector<std::pair<size_t, double> > q_;
266
- int idx_;
232
+ const size_t mask_;
233
+ std::vector<PosData> q_;
234
+ size_t idx_;
267
235
  };
268
236
 
269
237
  // Returns the minimum possible copy length that can improve the cost of any
270
238
  // future position.
271
- int ComputeMinimumCopyLength(const StartPosQueue& queue,
272
- const std::vector<ZopfliNode>& nodes,
273
- const ZopfliCostModel& model,
274
- size_t pos,
275
- double min_cost_cmd) {
239
+ static size_t ComputeMinimumCopyLength(const StartPosQueue& queue,
240
+ const ZopfliNode* nodes,
241
+ const ZopfliCostModel& model,
242
+ const size_t num_bytes,
243
+ const size_t pos) {
276
244
  // Compute the minimum possible cost of reaching any future position.
277
- const size_t start0 = queue.GetStartPos(0);
278
- double min_cost = (nodes[start0].cost +
279
- model.GetLiteralCosts(start0, pos) +
280
- min_cost_cmd);
281
- int len = 2;
282
- int next_len_bucket = 4;
283
- int next_len_offset = 10;
284
- while (pos + len < nodes.size() && nodes[pos + len].cost <= min_cost) {
245
+ const size_t start0 = queue.GetStartPosData(0).pos;
246
+ float min_cost = (nodes[start0].cost +
247
+ model.GetLiteralCosts(start0, pos) +
248
+ model.GetMinCostCmd());
249
+ size_t len = 2;
250
+ size_t next_len_bucket = 4;
251
+ size_t next_len_offset = 10;
252
+ while (pos + len <= num_bytes && nodes[pos + len].cost <= min_cost) {
285
253
  // We already reached (pos + len) with no more cost than the minimum
286
254
  // possible cost of reaching anything from this pos, so there is no point in
287
255
  // looking for lengths <= len.
@@ -289,7 +257,7 @@ int ComputeMinimumCopyLength(const StartPosQueue& queue,
289
257
  if (len == next_len_offset) {
290
258
  // We reached the next copy length code bucket, so we add one more
291
259
  // extra bit to the minimum cost.
292
- min_cost += 1.0;
260
+ min_cost += static_cast<float>(1.0);
293
261
  next_len_offset += next_len_bucket;
294
262
  next_len_bucket *= 2;
295
263
  }
@@ -297,193 +265,309 @@ int ComputeMinimumCopyLength(const StartPosQueue& queue,
297
265
  return len;
298
266
  }
299
267
 
300
- void ZopfliIterate(size_t num_bytes,
301
- size_t position,
302
- const uint8_t* ringbuffer,
303
- size_t ringbuffer_mask,
304
- const size_t max_backward_limit,
305
- const ZopfliCostModel& model,
306
- const std::vector<int>& num_matches,
307
- const std::vector<BackwardMatch>& matches,
308
- int* dist_cache,
309
- int* last_insert_len,
310
- Command* commands,
311
- size_t* num_commands,
312
- int* num_literals) {
313
- const Command * const orig_commands = commands;
314
-
315
- std::vector<ZopfliNode> nodes(num_bytes + 1);
316
- nodes[0].length = 0;
317
- nodes[0].cost = 0;
318
- memcpy(nodes[0].distance_cache, dist_cache, 4 * sizeof(dist_cache[0]));
319
-
320
- StartPosQueue queue(3);
321
- const double min_cost_cmd = model.GetMinCostCmd();
268
+ // Fills in dist_cache[0..3] with the last four distances (as defined by
269
+ // Section 4. of the Spec) that would be used at (block_start + pos) if we
270
+ // used the shortest path of commands from block_start, computed from
271
+ // nodes[0..pos]. The last four distances at block_start are in
272
+ // starting_dist_cach[0..3].
273
+ // REQUIRES: nodes[pos].cost < kInfinity
274
+ // REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant".
275
+ static void ComputeDistanceCache(const size_t block_start,
276
+ const size_t pos,
277
+ const size_t max_backward,
278
+ const int* starting_dist_cache,
279
+ const ZopfliNode* nodes,
280
+ int* dist_cache) {
281
+ int idx = 0;
282
+ size_t p = pos;
283
+ // Because of prerequisite, does at most (pos + 1) / 2 iterations.
284
+ while (idx < 4 && p > 0) {
285
+ const size_t clen = nodes[p].copy_length();
286
+ const size_t ilen = nodes[p].insert_length;
287
+ const size_t dist = nodes[p].copy_distance();
288
+ // Since block_start + p is the end position of the command, the copy part
289
+ // starts from block_start + p - clen. Distances that are greater than this
290
+ // or greater than max_backward are static dictionary references, and do
291
+ // not update the last distances. Also distance code 0 (last distance)
292
+ // does not update the last distances.
293
+ if (dist + clen <= block_start + p && dist <= max_backward &&
294
+ nodes[p].distance_code() > 0) {
295
+ dist_cache[idx++] = static_cast<int>(dist);
296
+ }
297
+ // Because of prerequisite, p >= clen + ilen >= 2.
298
+ p -= clen + ilen;
299
+ }
300
+ for (; idx < 4; ++idx) {
301
+ dist_cache[idx] = *starting_dist_cache++;
302
+ }
303
+ }
322
304
 
323
- size_t cur_match_pos = 0;
324
- for (size_t i = 0; i + 3 < num_bytes; i++) {
325
- size_t cur_ix = position + i;
326
- size_t cur_ix_masked = cur_ix & ringbuffer_mask;
327
- int max_distance = static_cast<int>(std::min(cur_ix, max_backward_limit));
328
- int max_length = static_cast<int>(num_bytes - i);
329
-
330
- queue.Push(i, nodes[i].cost - model.GetLiteralCosts(0, i));
331
-
332
- const int min_len = ComputeMinimumCopyLength(queue, nodes, model,
333
- i, min_cost_cmd);
334
-
335
- // Go over the command starting positions in order of increasing cost
336
- // difference.
337
- for (int k = 0; k < 5 && k < queue.size(); ++k) {
338
- const size_t start = queue.GetStartPos(k);
339
- const double start_costdiff =
340
- nodes[start].cost - model.GetLiteralCosts(0, start);
341
- const int* dist_cache2 = &nodes[start].distance_cache[0];
342
-
343
- // Look for last distance matches using the distance cache from this
344
- // starting position.
345
- int best_len = min_len - 1;
346
- for (int j = 0; j < kNumDistanceShortCodes; ++j) {
347
- const int idx = kDistanceCacheIndex[j];
348
- const int backward = dist_cache2[idx] + kDistanceCacheOffset[j];
349
- size_t prev_ix = cur_ix - backward;
350
- if (prev_ix >= cur_ix) {
351
- continue;
352
- }
353
- if (PREDICT_FALSE(backward > max_distance)) {
354
- continue;
355
- }
356
- prev_ix &= ringbuffer_mask;
305
+ static void UpdateNodes(const size_t num_bytes,
306
+ const size_t block_start,
307
+ const size_t pos,
308
+ const uint8_t* ringbuffer,
309
+ const size_t ringbuffer_mask,
310
+ const size_t max_backward_limit,
311
+ const int* starting_dist_cache,
312
+ const size_t num_matches,
313
+ const BackwardMatch* matches,
314
+ const ZopfliCostModel* model,
315
+ StartPosQueue* queue,
316
+ ZopfliNode* nodes) {
317
+ size_t cur_ix = block_start + pos;
318
+ size_t cur_ix_masked = cur_ix & ringbuffer_mask;
319
+ size_t max_distance = std::min(cur_ix, max_backward_limit);
320
+
321
+ if (nodes[pos].cost <= model->GetLiteralCosts(0, pos)) {
322
+ StartPosQueue::PosData posdata;
323
+ posdata.pos = pos;
324
+ posdata.costdiff = nodes[pos].cost - model->GetLiteralCosts(0, pos);
325
+ ComputeDistanceCache(block_start, pos, max_backward_limit,
326
+ starting_dist_cache, nodes, posdata.distance_cache);
327
+ queue->Push(posdata);
328
+ }
357
329
 
358
- if (cur_ix_masked + best_len > ringbuffer_mask ||
359
- prev_ix + best_len > ringbuffer_mask ||
360
- ringbuffer[cur_ix_masked + best_len] !=
361
- ringbuffer[prev_ix + best_len]) {
362
- continue;
363
- }
364
- const int len =
365
- FindMatchLengthWithLimit(&ringbuffer[prev_ix],
366
- &ringbuffer[cur_ix_masked],
367
- max_length);
368
- for (int l = best_len + 1; l <= len; ++l) {
369
- const int inslen = static_cast<int>(i - start);
370
- double cmd_cost = model.GetCommandCost(j, l, inslen);
371
- double cost = start_costdiff + cmd_cost + model.GetLiteralCosts(0, i);
372
- if (cost < nodes[i + l].cost) {
373
- UpdateZopfliNode(&nodes[0], i, start, l, l, backward, j,
374
- max_distance, dist_cache2, cost);
375
- }
376
- best_len = l;
377
- }
330
+ const size_t min_len = ComputeMinimumCopyLength(
331
+ *queue, nodes, *model, num_bytes, pos);
332
+
333
+ // Go over the command starting positions in order of increasing cost
334
+ // difference.
335
+ for (size_t k = 0; k < 5 && k < queue->size(); ++k) {
336
+ const StartPosQueue::PosData& posdata = queue->GetStartPosData(k);
337
+ const size_t start = posdata.pos;
338
+ const float start_costdiff = posdata.costdiff;
339
+
340
+ // Look for last distance matches using the distance cache from this
341
+ // starting position.
342
+ size_t best_len = min_len - 1;
343
+ for (size_t j = 0; j < kNumDistanceShortCodes; ++j) {
344
+ const size_t idx = kDistanceCacheIndex[j];
345
+ const size_t backward = static_cast<size_t>(posdata.distance_cache[idx] +
346
+ kDistanceCacheOffset[j]);
347
+ size_t prev_ix = cur_ix - backward;
348
+ if (prev_ix >= cur_ix) {
349
+ continue;
350
+ }
351
+ if (PREDICT_FALSE(backward > max_distance)) {
352
+ continue;
378
353
  }
354
+ prev_ix &= ringbuffer_mask;
379
355
 
380
- // At higher iterations look only for new last distance matches, since
381
- // looking only for new command start positions with the same distances
382
- // does not help much.
383
- if (k >= 2) continue;
384
-
385
- // Loop through all possible copy lengths at this position.
386
- int len = min_len;
387
- for (int j = 0; j < num_matches[i]; ++j) {
388
- BackwardMatch match = matches[cur_match_pos + j];
389
- int dist = match.distance;
390
- bool is_dictionary_match = dist > max_distance;
391
- // We already tried all possible last distance matches, so we can use
392
- // normal distance code here.
393
- int dist_code = dist + 15;
394
- // Try all copy lengths up until the maximum copy length corresponding
395
- // to this distance. If the distance refers to the static dictionary, or
396
- // the maximum length is long enough, try only one maximum length.
397
- int max_len = match.length();
398
- if (len < max_len && (is_dictionary_match || max_len > kMaxZopfliLen)) {
399
- len = max_len;
400
- }
401
- for (; len <= max_len; ++len) {
402
- int len_code = is_dictionary_match ? match.length_code() : len;
403
- const int inslen = static_cast<int>(i - start);
404
- double cmd_cost = model.GetCommandCost(dist_code, len_code, inslen);
405
- double cost = start_costdiff + cmd_cost + model.GetLiteralCosts(0, i);
406
- if (cost < nodes[i + len].cost) {
407
- UpdateZopfliNode(&nodes[0], i, start, len, len_code, dist,
408
- dist_code, max_distance, dist_cache2, cost);
409
- }
356
+ if (cur_ix_masked + best_len > ringbuffer_mask ||
357
+ prev_ix + best_len > ringbuffer_mask ||
358
+ ringbuffer[cur_ix_masked + best_len] !=
359
+ ringbuffer[prev_ix + best_len]) {
360
+ continue;
361
+ }
362
+ const size_t len =
363
+ FindMatchLengthWithLimit(&ringbuffer[prev_ix],
364
+ &ringbuffer[cur_ix_masked],
365
+ num_bytes - pos);
366
+ for (size_t l = best_len + 1; l <= len; ++l) {
367
+ const size_t inslen = pos - start;
368
+ float cmd_cost = model->GetCommandCost(j, l, inslen);
369
+ float cost = start_costdiff + cmd_cost + model->GetLiteralCosts(0, pos);
370
+ if (cost < nodes[pos + l].cost) {
371
+ UpdateZopfliNode(&nodes[0], pos, start, l, l, backward, j + 1, cost);
410
372
  }
373
+ best_len = l;
411
374
  }
412
375
  }
413
376
 
414
- cur_match_pos += num_matches[i];
415
-
416
- // The zopflification can be too slow in case of very long lengths, so in
417
- // such case skip it all, it does not cost a lot of compression ratio.
418
- if (num_matches[i] == 1 &&
419
- matches[cur_match_pos - 1].length() > kMaxZopfliLen) {
420
- i += matches[cur_match_pos - 1].length() - 1;
421
- queue.Clear();
377
+ // At higher iterations look only for new last distance matches, since
378
+ // looking only for new command start positions with the same distances
379
+ // does not help much.
380
+ if (k >= 2) continue;
381
+
382
+ // Loop through all possible copy lengths at this position.
383
+ size_t len = min_len;
384
+ for (size_t j = 0; j < num_matches; ++j) {
385
+ BackwardMatch match = matches[j];
386
+ size_t dist = match.distance;
387
+ bool is_dictionary_match = dist > max_distance;
388
+ // We already tried all possible last distance matches, so we can use
389
+ // normal distance code here.
390
+ size_t dist_code = dist + 15;
391
+ // Try all copy lengths up until the maximum copy length corresponding
392
+ // to this distance. If the distance refers to the static dictionary, or
393
+ // the maximum length is long enough, try only one maximum length.
394
+ size_t max_len = match.length();
395
+ if (len < max_len && (is_dictionary_match || max_len > kMaxZopfliLen)) {
396
+ len = max_len;
397
+ }
398
+ for (; len <= max_len; ++len) {
399
+ size_t len_code = is_dictionary_match ? match.length_code() : len;
400
+ const size_t inslen = pos - start;
401
+ float cmd_cost = model->GetCommandCost(dist_code, len_code, inslen);
402
+ float cost = start_costdiff + cmd_cost + model->GetLiteralCosts(0, pos);
403
+ if (cost < nodes[pos + len].cost) {
404
+ UpdateZopfliNode(&nodes[0], pos, start, len, len_code, dist, 0, cost);
405
+ }
406
+ }
422
407
  }
423
408
  }
409
+ }
424
410
 
425
- std::vector<int> backwards;
411
+ static void ComputeShortestPathFromNodes(size_t num_bytes,
412
+ const ZopfliNode* nodes,
413
+ std::vector<uint32_t>* path) {
414
+ std::vector<uint32_t> backwards(num_bytes / 2 + 1);
426
415
  size_t index = num_bytes;
427
416
  while (nodes[index].cost == kInfinity) --index;
428
- while (index > 0) {
429
- int len = nodes[index].length + nodes[index].insert_length;
430
- backwards.push_back(len);
417
+ size_t num_commands = 0;
418
+ while (index != 0) {
419
+ size_t len = nodes[index].command_length();
420
+ backwards[num_commands++] = static_cast<uint32_t>(len);
431
421
  index -= len;
432
422
  }
433
-
434
- std::vector<int> path;
435
- for (size_t i = backwards.size(); i > 0; i--) {
436
- path.push_back(backwards[i - 1]);
423
+ path->resize(num_commands);
424
+ for (size_t i = num_commands, j = 0; i > 0; --i, ++j) {
425
+ (*path)[j] = backwards[i - 1];
437
426
  }
427
+ }
438
428
 
429
+ void ZopfliCreateCommands(const size_t num_bytes,
430
+ const size_t block_start,
431
+ const size_t max_backward_limit,
432
+ const std::vector<uint32_t>& path,
433
+ const ZopfliNode* nodes,
434
+ int* dist_cache,
435
+ size_t* last_insert_len,
436
+ Command* commands,
437
+ size_t* num_literals) {
439
438
  size_t pos = 0;
440
439
  for (size_t i = 0; i < path.size(); i++) {
441
440
  const ZopfliNode& next = nodes[pos + path[i]];
442
- int copy_length = next.length;
443
- int insert_length = next.insert_length;
441
+ size_t copy_length = next.copy_length();
442
+ size_t insert_length = next.insert_length;
444
443
  pos += insert_length;
445
444
  if (i == 0) {
446
445
  insert_length += *last_insert_len;
447
446
  *last_insert_len = 0;
448
447
  }
449
- int distance = next.distance;
450
- int len_code = next.length_code;
451
- int max_distance =
452
- static_cast<int>(std::min(position + pos, max_backward_limit));
448
+ size_t distance = next.copy_distance();
449
+ size_t len_code = next.length_code();
450
+ size_t max_distance = std::min(block_start + pos, max_backward_limit);
453
451
  bool is_dictionary = (distance > max_distance);
454
- int dist_code = next.distance_code;
452
+ size_t dist_code = next.distance_code();
455
453
 
456
454
  Command cmd(insert_length, copy_length, len_code, dist_code);
457
- *commands++ = cmd;
455
+ commands[i] = cmd;
458
456
 
459
457
  if (!is_dictionary && dist_code > 0) {
460
458
  dist_cache[3] = dist_cache[2];
461
459
  dist_cache[2] = dist_cache[1];
462
460
  dist_cache[1] = dist_cache[0];
463
- dist_cache[0] = distance;
461
+ dist_cache[0] = static_cast<int>(distance);
464
462
  }
465
463
 
466
464
  *num_literals += insert_length;
467
- insert_length = 0;
468
465
  pos += copy_length;
469
466
  }
470
- *last_insert_len += static_cast<int>(num_bytes - pos);
471
- *num_commands += (commands - orig_commands);
467
+ *last_insert_len += num_bytes - pos;
468
+ }
469
+
470
+ static void ZopfliIterate(size_t num_bytes,
471
+ size_t position,
472
+ const uint8_t* ringbuffer,
473
+ size_t ringbuffer_mask,
474
+ const size_t max_backward_limit,
475
+ const int* dist_cache,
476
+ const ZopfliCostModel& model,
477
+ const std::vector<uint32_t>& num_matches,
478
+ const std::vector<BackwardMatch>& matches,
479
+ ZopfliNode* nodes,
480
+ std::vector<uint32_t>* path) {
481
+ nodes[0].length = 0;
482
+ nodes[0].cost = 0;
483
+ StartPosQueue queue(3);
484
+ size_t cur_match_pos = 0;
485
+ for (size_t i = 0; i + 3 < num_bytes; i++) {
486
+ UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask,
487
+ max_backward_limit, dist_cache, num_matches[i],
488
+ &matches[cur_match_pos], &model, &queue, &nodes[0]);
489
+ cur_match_pos += num_matches[i];
490
+ // The zopflification can be too slow in case of very long lengths, so in
491
+ // such case skip it all, it does not cost a lot of compression ratio.
492
+ if (num_matches[i] == 1 &&
493
+ matches[cur_match_pos - 1].length() > kMaxZopfliLen) {
494
+ i += matches[cur_match_pos - 1].length() - 1;
495
+ queue.Clear();
496
+ }
497
+ }
498
+ ComputeShortestPathFromNodes(num_bytes, &nodes[0], path);
499
+ }
500
+
501
+
502
+ void ZopfliComputeShortestPath(size_t num_bytes,
503
+ size_t position,
504
+ const uint8_t* ringbuffer,
505
+ size_t ringbuffer_mask,
506
+ const size_t max_backward_limit,
507
+ const int* dist_cache,
508
+ Hashers::H10* hasher,
509
+ ZopfliNode* nodes,
510
+ std::vector<uint32_t>* path) {
511
+ nodes[0].length = 0;
512
+ nodes[0].cost = 0;
513
+ ZopfliCostModel* model = new ZopfliCostModel;
514
+ model->SetFromLiteralCosts(num_bytes, position,
515
+ ringbuffer, ringbuffer_mask);
516
+ StartPosQueue queue(3);
517
+ BackwardMatch matches[Hashers::H10::kMaxNumMatches];
518
+ for (size_t i = 0; i + 3 < num_bytes; i++) {
519
+ const size_t max_distance = std::min(position + i, max_backward_limit);
520
+ size_t num_matches = hasher->FindAllMatches(
521
+ ringbuffer, ringbuffer_mask, position + i, num_bytes - i, max_distance,
522
+ matches);
523
+ if (num_matches > 0 &&
524
+ matches[num_matches - 1].length() > kMaxZopfliLen) {
525
+ matches[0] = matches[num_matches - 1];
526
+ num_matches = 1;
527
+ }
528
+ UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask,
529
+ max_backward_limit, dist_cache, num_matches, matches,
530
+ model, &queue, nodes);
531
+ if (num_matches == 1 && matches[0].length() > kMaxZopfliLen) {
532
+ for (size_t j = 1; j < matches[0].length() && i + 4 < num_bytes; ++j) {
533
+ ++i;
534
+ if (matches[0].length() - j < 64 &&
535
+ num_bytes - i >= kMaxTreeCompLength) {
536
+ hasher->Store(ringbuffer, ringbuffer_mask, position + i);
537
+ }
538
+ }
539
+ queue.Clear();
540
+ }
541
+ }
542
+ delete model;
543
+ ComputeShortestPathFromNodes(num_bytes, nodes, path);
472
544
  }
473
545
 
474
546
  template<typename Hasher>
475
547
  void CreateBackwardReferences(size_t num_bytes,
476
548
  size_t position,
549
+ bool is_last,
477
550
  const uint8_t* ringbuffer,
478
551
  size_t ringbuffer_mask,
479
- const size_t max_backward_limit,
480
552
  const int quality,
553
+ const int lgwin,
481
554
  Hasher* hasher,
482
555
  int* dist_cache,
483
- int* last_insert_len,
556
+ size_t* last_insert_len,
484
557
  Command* commands,
485
558
  size_t* num_commands,
486
- int* num_literals) {
559
+ size_t* num_literals) {
560
+ // Set maximum distance, see section 9.1. of the spec.
561
+ const size_t max_backward_limit = (1 << lgwin) - 16;
562
+
563
+ // Choose which init method is faster.
564
+ // memset is about 100 times faster than hasher->InitForData().
565
+ const size_t kMaxBytesForPartialHashInit = Hasher::kHashMapSize >> 7;
566
+ if (position == 0 && is_last && num_bytes <= kMaxBytesForPartialHashInit) {
567
+ hasher->InitForData(ringbuffer, num_bytes);
568
+ } else {
569
+ hasher->Init();
570
+ }
487
571
  if (num_bytes >= 3 && position >= 3) {
488
572
  // Prepare the hashes for three last bytes of the last write.
489
573
  // These could not be calculated before, since they require knowledge
@@ -496,7 +580,7 @@ void CreateBackwardReferences(size_t num_bytes,
496
580
  static_cast<uint32_t>(position - 1));
497
581
  }
498
582
  const Command * const orig_commands = commands;
499
- int insert_length = *last_insert_len;
583
+ size_t insert_length = *last_insert_len;
500
584
  size_t i = position & ringbuffer_mask;
501
585
  const size_t i_diff = position - i;
502
586
  const size_t i_end = i + num_bytes;
@@ -506,15 +590,14 @@ void CreateBackwardReferences(size_t num_bytes,
506
590
  size_t apply_random_heuristics = i + random_heuristics_window_size;
507
591
 
508
592
  // Minimum score to accept a backward reference.
509
- const int kMinScore = 4.0;
593
+ const double kMinScore = 4.0;
510
594
 
511
595
  while (i + Hasher::kHashTypeLength - 1 < i_end) {
512
- int max_length = static_cast<int>(i_end - i);
513
- int max_distance =
514
- static_cast<int>(std::min(i + i_diff, max_backward_limit));
515
- int best_len = 0;
516
- int best_len_code = 0;
517
- int best_dist = 0;
596
+ size_t max_length = i_end - i;
597
+ size_t max_distance = std::min(i + i_diff, max_backward_limit);
598
+ size_t best_len = 0;
599
+ size_t best_len_code = 0;
600
+ size_t best_dist = 0;
518
601
  double best_score = kMinScore;
519
602
  bool match_found = hasher->FindLongestMatch(
520
603
  ringbuffer, ringbuffer_mask,
@@ -525,13 +608,12 @@ void CreateBackwardReferences(size_t num_bytes,
525
608
  int delayed_backward_references_in_row = 0;
526
609
  for (;;) {
527
610
  --max_length;
528
- int best_len_2 = quality < 5 ? std::min(best_len - 1, max_length) : 0;
529
- int best_len_code_2 = 0;
530
- int best_dist_2 = 0;
611
+ size_t best_len_2 =
612
+ quality < 5 ? std::min(best_len - 1, max_length) : 0;
613
+ size_t best_len_code_2 = 0;
614
+ size_t best_dist_2 = 0;
531
615
  double best_score_2 = kMinScore;
532
- max_distance =
533
- static_cast<int>(std::min(i + i_diff + 1, max_backward_limit));
534
- hasher->Store(ringbuffer + i, static_cast<uint32_t>(i + i_diff));
616
+ max_distance = std::min(i + i_diff + 1, max_backward_limit);
535
617
  match_found = hasher->FindLongestMatch(
536
618
  ringbuffer, ringbuffer_mask,
537
619
  dist_cache, static_cast<uint32_t>(i + i_diff + 1),
@@ -555,15 +637,15 @@ void CreateBackwardReferences(size_t num_bytes,
555
637
  }
556
638
  apply_random_heuristics =
557
639
  i + 2 * best_len + random_heuristics_window_size;
558
- max_distance = static_cast<int>(std::min(i + i_diff, max_backward_limit));
640
+ max_distance = std::min(i + i_diff, max_backward_limit);
559
641
  // The first 16 codes are special shortcodes, and the minimum offset is 1.
560
- int distance_code =
642
+ size_t distance_code =
561
643
  ComputeDistanceCode(best_dist, max_distance, quality, dist_cache);
562
644
  if (best_dist <= max_distance && distance_code > 0) {
563
645
  dist_cache[3] = dist_cache[2];
564
646
  dist_cache[2] = dist_cache[1];
565
647
  dist_cache[1] = dist_cache[0];
566
- dist_cache[0] = best_dist;
648
+ dist_cache[0] = static_cast<int>(best_dist);
567
649
  }
568
650
  Command cmd(insert_length, best_len, best_len_code, distance_code);
569
651
  *commands++ = cmd;
@@ -571,14 +653,13 @@ void CreateBackwardReferences(size_t num_bytes,
571
653
  insert_length = 0;
572
654
  // Put the hash keys into the table, if there are enough
573
655
  // bytes left.
574
- for (int j = 1; j < best_len; ++j) {
656
+ for (size_t j = 2; j < best_len; ++j) {
575
657
  hasher->Store(&ringbuffer[i + j],
576
658
  static_cast<uint32_t>(i + i_diff + j));
577
659
  }
578
660
  i += best_len;
579
661
  } else {
580
662
  ++insert_length;
581
- hasher->Store(ringbuffer + i, static_cast<uint32_t>(i + i_diff));
582
663
  ++i;
583
664
  // If we have not seen matches for a long time, we can skip some
584
665
  // match lookups. Unsuccessful match lookups are very very expensive
@@ -608,76 +689,91 @@ void CreateBackwardReferences(size_t num_bytes,
608
689
  }
609
690
  }
610
691
  }
611
- insert_length += static_cast<int>(i_end - i);
692
+ insert_length += i_end - i;
612
693
  *last_insert_len = insert_length;
613
- *num_commands += commands - orig_commands;
694
+ *num_commands += static_cast<size_t>(commands - orig_commands);
614
695
  }
615
696
 
616
697
  void CreateBackwardReferences(size_t num_bytes,
617
698
  size_t position,
699
+ bool is_last,
618
700
  const uint8_t* ringbuffer,
619
701
  size_t ringbuffer_mask,
620
- const size_t max_backward_limit,
621
702
  const int quality,
703
+ const int lgwin,
622
704
  Hashers* hashers,
623
705
  int hash_type,
624
706
  int* dist_cache,
625
- int* last_insert_len,
707
+ size_t* last_insert_len,
626
708
  Command* commands,
627
709
  size_t* num_commands,
628
- int* num_literals) {
710
+ size_t* num_literals) {
629
711
  bool zopflify = quality > 9;
630
712
  if (zopflify) {
631
- Hashers::H9* hasher = hashers->hash_h9;
632
- if (num_bytes >= 3 && position >= 3) {
633
- // Prepare the hashes for three last bytes of the last write.
634
- // These could not be calculated before, since they require knowledge
635
- // of both the previous and the current block.
636
- hasher->Store(&ringbuffer[(position - 3) & ringbuffer_mask],
637
- static_cast<uint32_t>(position - 3));
638
- hasher->Store(&ringbuffer[(position - 2) & ringbuffer_mask],
639
- static_cast<uint32_t>(position - 2));
640
- hasher->Store(&ringbuffer[(position - 1) & ringbuffer_mask],
641
- static_cast<uint32_t>(position - 1));
713
+ Hashers::H10* hasher = hashers->hash_h10;
714
+ hasher->Init(lgwin, position, num_bytes, is_last);
715
+ hasher->StitchToPreviousBlock(num_bytes, position,
716
+ ringbuffer, ringbuffer_mask);
717
+ // Set maximum distance, see section 9.1. of the spec.
718
+ const size_t max_backward_limit = (1 << lgwin) - 16;
719
+ if (quality == 10) {
720
+ std::vector<ZopfliNode> nodes(num_bytes + 1);
721
+ std::vector<uint32_t> path;
722
+ ZopfliComputeShortestPath(num_bytes, position,
723
+ ringbuffer, ringbuffer_mask,
724
+ max_backward_limit, dist_cache, hasher,
725
+ &nodes[0], &path);
726
+ ZopfliCreateCommands(num_bytes, position, max_backward_limit, path,
727
+ &nodes[0], dist_cache, last_insert_len, commands,
728
+ num_literals);
729
+ *num_commands += path.size();
730
+ return;
642
731
  }
643
- std::vector<int> num_matches(num_bytes);
644
- std::vector<BackwardMatch> matches(3 * num_bytes);
732
+ std::vector<uint32_t> num_matches(num_bytes);
733
+ std::vector<BackwardMatch> matches(4 * num_bytes);
645
734
  size_t cur_match_pos = 0;
646
735
  for (size_t i = 0; i + 3 < num_bytes; ++i) {
647
- int max_distance =
648
- static_cast<int>(std::min(position + i, max_backward_limit));
649
- int max_length = static_cast<int>(num_bytes - i);
650
- // Ensure that we have at least kMaxZopfliLen free slots.
651
- if (matches.size() < cur_match_pos + kMaxZopfliLen) {
652
- matches.resize(cur_match_pos + kMaxZopfliLen);
736
+ size_t max_distance = std::min(position + i, max_backward_limit);
737
+ size_t max_length = num_bytes - i;
738
+ // Ensure that we have enough free slots.
739
+ if (matches.size() < cur_match_pos + Hashers::H10::kMaxNumMatches) {
740
+ matches.resize(cur_match_pos + Hashers::H10::kMaxNumMatches);
741
+ }
742
+ size_t num_found_matches = hasher->FindAllMatches(
743
+ ringbuffer, ringbuffer_mask, position + i, max_length, max_distance,
744
+ &matches[cur_match_pos]);
745
+ const size_t cur_match_end = cur_match_pos + num_found_matches;
746
+ for (size_t j = cur_match_pos; j + 1 < cur_match_end; ++j) {
747
+ assert(matches[j].length() < matches[j + 1].length());
748
+ assert(matches[j].distance > max_distance ||
749
+ matches[j].distance <= matches[j + 1].distance);
653
750
  }
654
- hasher->FindAllMatches(
655
- ringbuffer, ringbuffer_mask,
656
- static_cast<uint32_t>(position + i), max_length, max_distance,
657
- &num_matches[i], &matches[cur_match_pos]);
658
- hasher->Store(&ringbuffer[(position + i) & ringbuffer_mask],
659
- static_cast<uint32_t>(position + i));
660
- cur_match_pos += num_matches[i];
661
- if (num_matches[i] == 1) {
662
- const int match_len = matches[cur_match_pos - 1].length();
751
+ num_matches[i] = static_cast<uint32_t>(num_found_matches);
752
+ if (num_found_matches > 0) {
753
+ const size_t match_len = matches[cur_match_end - 1].length();
663
754
  if (match_len > kMaxZopfliLen) {
664
- for (int j = 1; j < match_len; ++j) {
755
+ matches[cur_match_pos++] = matches[cur_match_end - 1];
756
+ num_matches[i] = 1;
757
+ for (size_t j = 1; j < match_len; ++j) {
665
758
  ++i;
666
- hasher->Store(&ringbuffer[(position + i) & ringbuffer_mask],
667
- static_cast<uint32_t>(position + i));
759
+ if (match_len - j < 64 && num_bytes - i >= kMaxTreeCompLength) {
760
+ hasher->Store(ringbuffer, ringbuffer_mask, position + i);
761
+ }
668
762
  num_matches[i] = 0;
669
763
  }
764
+ } else {
765
+ cur_match_pos = cur_match_end;
670
766
  }
671
767
  }
672
768
  }
673
- int orig_num_literals = *num_literals;
674
- int orig_last_insert_len = *last_insert_len;
769
+ size_t orig_num_literals = *num_literals;
770
+ size_t orig_last_insert_len = *last_insert_len;
675
771
  int orig_dist_cache[4] = {
676
772
  dist_cache[0], dist_cache[1], dist_cache[2], dist_cache[3]
677
773
  };
678
774
  size_t orig_num_commands = *num_commands;
679
- static const int kIterations = 2;
680
- for (int i = 0; i < kIterations; i++) {
775
+ static const size_t kIterations = 2;
776
+ for (size_t i = 0; i < kIterations; i++) {
681
777
  ZopfliCostModel model;
682
778
  if (i == 0) {
683
779
  model.SetFromLiteralCosts(num_bytes, position,
@@ -692,67 +788,67 @@ void CreateBackwardReferences(size_t num_bytes,
692
788
  *num_literals = orig_num_literals;
693
789
  *last_insert_len = orig_last_insert_len;
694
790
  memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
791
+ std::vector<ZopfliNode> nodes(num_bytes + 1);
792
+ std::vector<uint32_t> path;
695
793
  ZopfliIterate(num_bytes, position, ringbuffer, ringbuffer_mask,
696
- max_backward_limit, model, num_matches, matches, dist_cache,
697
- last_insert_len, commands, num_commands, num_literals);
794
+ max_backward_limit, dist_cache, model, num_matches, matches,
795
+ &nodes[0], &path);
796
+ ZopfliCreateCommands(num_bytes, position, max_backward_limit, path,
797
+ &nodes[0], dist_cache, last_insert_len, commands,
798
+ num_literals);
799
+ *num_commands += path.size();
698
800
  }
699
801
  return;
700
802
  }
701
803
 
702
804
  switch (hash_type) {
703
- case 1:
704
- CreateBackwardReferences<Hashers::H1>(
705
- num_bytes, position, ringbuffer, ringbuffer_mask, max_backward_limit,
706
- quality, hashers->hash_h1, dist_cache, last_insert_len,
707
- commands, num_commands, num_literals);
708
- break;
709
805
  case 2:
710
806
  CreateBackwardReferences<Hashers::H2>(
711
- num_bytes, position, ringbuffer, ringbuffer_mask, max_backward_limit,
712
- quality, hashers->hash_h2, dist_cache, last_insert_len,
713
- commands, num_commands, num_literals);
807
+ num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
808
+ quality, lgwin, hashers->hash_h2, dist_cache,
809
+ last_insert_len, commands, num_commands, num_literals);
714
810
  break;
715
811
  case 3:
716
812
  CreateBackwardReferences<Hashers::H3>(
717
- num_bytes, position, ringbuffer, ringbuffer_mask, max_backward_limit,
718
- quality, hashers->hash_h3, dist_cache, last_insert_len,
719
- commands, num_commands, num_literals);
813
+ num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
814
+ quality, lgwin, hashers->hash_h3, dist_cache,
815
+ last_insert_len, commands, num_commands, num_literals);
720
816
  break;
721
817
  case 4:
722
818
  CreateBackwardReferences<Hashers::H4>(
723
- num_bytes, position, ringbuffer, ringbuffer_mask, max_backward_limit,
724
- quality, hashers->hash_h4, dist_cache, last_insert_len,
725
- commands, num_commands, num_literals);
819
+ num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
820
+ quality, lgwin, hashers->hash_h4, dist_cache,
821
+ last_insert_len, commands, num_commands, num_literals);
726
822
  break;
727
823
  case 5:
728
824
  CreateBackwardReferences<Hashers::H5>(
729
- num_bytes, position, ringbuffer, ringbuffer_mask, max_backward_limit,
730
- quality, hashers->hash_h5, dist_cache, last_insert_len,
731
- commands, num_commands, num_literals);
825
+ num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
826
+ quality, lgwin, hashers->hash_h5, dist_cache,
827
+ last_insert_len, commands, num_commands, num_literals);
732
828
  break;
733
829
  case 6:
734
830
  CreateBackwardReferences<Hashers::H6>(
735
- num_bytes, position, ringbuffer, ringbuffer_mask, max_backward_limit,
736
- quality, hashers->hash_h6, dist_cache, last_insert_len,
737
- commands, num_commands, num_literals);
831
+ num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
832
+ quality, lgwin, hashers->hash_h6, dist_cache,
833
+ last_insert_len, commands, num_commands, num_literals);
738
834
  break;
739
835
  case 7:
740
836
  CreateBackwardReferences<Hashers::H7>(
741
- num_bytes, position, ringbuffer, ringbuffer_mask, max_backward_limit,
742
- quality, hashers->hash_h7, dist_cache, last_insert_len,
743
- commands, num_commands, num_literals);
837
+ num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
838
+ quality, lgwin, hashers->hash_h7, dist_cache,
839
+ last_insert_len, commands, num_commands, num_literals);
744
840
  break;
745
841
  case 8:
746
842
  CreateBackwardReferences<Hashers::H8>(
747
- num_bytes, position, ringbuffer, ringbuffer_mask, max_backward_limit,
748
- quality, hashers->hash_h8, dist_cache, last_insert_len,
749
- commands, num_commands, num_literals);
843
+ num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
844
+ quality, lgwin, hashers->hash_h8, dist_cache,
845
+ last_insert_len, commands, num_commands, num_literals);
750
846
  break;
751
847
  case 9:
752
848
  CreateBackwardReferences<Hashers::H9>(
753
- num_bytes, position, ringbuffer, ringbuffer_mask, max_backward_limit,
754
- quality, hashers->hash_h9, dist_cache, last_insert_len,
755
- commands, num_commands, num_literals);
849
+ num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
850
+ quality, lgwin, hashers->hash_h9, dist_cache,
851
+ last_insert_len, commands, num_commands, num_literals);
756
852
  break;
757
853
  default:
758
854
  break;