brotli 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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;