Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: third_party/brotli/enc/backward_references.c

Issue 2537133002: Update brotli to v1.0.0-snapshot. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /* Copyright 2013 Google Inc. All Rights Reserved.
2
3 Distributed under MIT license.
4 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5 */
6
7 /* Function to find backward reference copies. */
8
9 #include "./backward_references.h"
10
11 #include <math.h> /* INFINITY */
12 #include <string.h> /* memcpy, memset */
13
14 #include "../common/constants.h"
15 #include <brotli/types.h>
16 #include "./command.h"
17 #include "./fast_log.h"
18 #include "./find_match_length.h"
19 #include "./literal_cost.h"
20 #include "./memory.h"
21 #include "./port.h"
22 #include "./prefix.h"
23 #include "./quality.h"
24
25 #if defined(__cplusplus) || defined(c_plusplus)
26 extern "C" {
27 #endif
28
29 #ifdef INFINITY
30 static const float kInfinity = INFINITY;
31 #else
32 static const float kInfinity = 3.4028e38f;
33 #endif
34
35 void BrotliInitZopfliNodes(ZopfliNode* array, size_t length) {
36 ZopfliNode stub;
37 size_t i;
38 stub.length = 1;
39 stub.distance = 0;
40 stub.insert_length = 0;
41 stub.u.cost = kInfinity;
42 for (i = 0; i < length; ++i) array[i] = stub;
43 }
44
45 static BROTLI_INLINE uint32_t ZopfliNodeCopyLength(const ZopfliNode* self) {
46 return self->length & 0xffffff;
47 }
48
49 static BROTLI_INLINE uint32_t ZopfliNodeLengthCode(const ZopfliNode* self) {
50 const uint32_t modifier = self->length >> 24;
51 return ZopfliNodeCopyLength(self) + 9u - modifier;
52 }
53
54 static BROTLI_INLINE uint32_t ZopfliNodeCopyDistance(const ZopfliNode* self) {
55 return self->distance & 0x1ffffff;
56 }
57
58 static BROTLI_INLINE uint32_t ZopfliNodeDistanceCode(const ZopfliNode* self) {
59 const uint32_t short_code = self->distance >> 25;
60 return short_code == 0 ?
61 ZopfliNodeCopyDistance(self) + BROTLI_NUM_DISTANCE_SHORT_CODES - 1 :
62 short_code - 1;
63 }
64
65 static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
66 return ZopfliNodeCopyLength(self) + self->insert_length;
67 }
68
69 /* Histogram based cost model for zopflification. */
70 typedef struct ZopfliCostModel {
71 /* The insert and copy length symbols. */
72 float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS];
73 float cost_dist_[BROTLI_NUM_DISTANCE_SYMBOLS];
74 /* Cumulative costs of literals per position in the stream. */
75 float* literal_costs_;
76 float min_cost_cmd_;
77 size_t num_bytes_;
78 } ZopfliCostModel;
79
80 static void InitZopfliCostModel(
81 MemoryManager* m, ZopfliCostModel* self, size_t num_bytes) {
82 self->num_bytes_ = num_bytes;
83 self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
84 if (BROTLI_IS_OOM(m)) return;
85 }
86
87 static void CleanupZopfliCostModel(MemoryManager* m, ZopfliCostModel* self) {
88 BROTLI_FREE(m, self->literal_costs_);
89 }
90
91 static void SetCost(const uint32_t* histogram, size_t histogram_size,
92 float* cost) {
93 size_t sum = 0;
94 float log2sum;
95 size_t i;
96 for (i = 0; i < histogram_size; i++) {
97 sum += histogram[i];
98 }
99 log2sum = (float)FastLog2(sum);
100 for (i = 0; i < histogram_size; i++) {
101 if (histogram[i] == 0) {
102 cost[i] = log2sum + 2;
103 continue;
104 }
105
106 /* Shannon bits for this symbol. */
107 cost[i] = log2sum - (float)FastLog2(histogram[i]);
108
109 /* Cannot be coded with less than 1 bit */
110 if (cost[i] < 1) cost[i] = 1;
111 }
112 }
113
114 static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
115 size_t position,
116 const uint8_t* ringbuffer,
117 size_t ringbuffer_mask,
118 const Command* commands,
119 size_t num_commands,
120 size_t last_insert_len) {
121 uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
122 uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
123 uint32_t histogram_dist[BROTLI_NUM_DISTANCE_SYMBOLS];
124 float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
125 size_t pos = position - last_insert_len;
126 float min_cost_cmd = kInfinity;
127 size_t i;
128 float* cost_cmd = self->cost_cmd_;
129
130 memset(histogram_literal, 0, sizeof(histogram_literal));
131 memset(histogram_cmd, 0, sizeof(histogram_cmd));
132 memset(histogram_dist, 0, sizeof(histogram_dist));
133
134 for (i = 0; i < num_commands; i++) {
135 size_t inslength = commands[i].insert_len_;
136 size_t copylength = CommandCopyLen(&commands[i]);
137 size_t distcode = commands[i].dist_prefix_;
138 size_t cmdcode = commands[i].cmd_prefix_;
139 size_t j;
140
141 histogram_cmd[cmdcode]++;
142 if (cmdcode >= 128) histogram_dist[distcode]++;
143
144 for (j = 0; j < inslength; j++) {
145 histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
146 }
147
148 pos += inslength + copylength;
149 }
150
151 SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, cost_literal);
152 SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, cost_cmd);
153 SetCost(histogram_dist, BROTLI_NUM_DISTANCE_SYMBOLS, self->cost_dist_);
154
155 for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
156 min_cost_cmd = BROTLI_MIN(float, min_cost_cmd, cost_cmd[i]);
157 }
158 self->min_cost_cmd_ = min_cost_cmd;
159
160 {
161 float* literal_costs = self->literal_costs_;
162 size_t num_bytes = self->num_bytes_;
163 literal_costs[0] = 0.0;
164 for (i = 0; i < num_bytes; ++i) {
165 literal_costs[i + 1] = literal_costs[i] +
166 cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
167 }
168 }
169 }
170
171 static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
172 size_t position,
173 const uint8_t* ringbuffer,
174 size_t ringbuffer_mask) {
175 float* literal_costs = self->literal_costs_;
176 float* cost_dist = self->cost_dist_;
177 float* cost_cmd = self->cost_cmd_;
178 size_t num_bytes = self->num_bytes_;
179 size_t i;
180 BrotliEstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask,
181 ringbuffer, &literal_costs[1]);
182 literal_costs[0] = 0.0;
183 for (i = 0; i < num_bytes; ++i) {
184 literal_costs[i + 1] += literal_costs[i];
185 }
186 for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
187 cost_cmd[i] = (float)FastLog2(11 + (uint32_t)i);
188 }
189 for (i = 0; i < BROTLI_NUM_DISTANCE_SYMBOLS; ++i) {
190 cost_dist[i] = (float)FastLog2(20 + (uint32_t)i);
191 }
192 self->min_cost_cmd_ = (float)FastLog2(11);
193 }
194
195 static BROTLI_INLINE float ZopfliCostModelGetCommandCost(
196 const ZopfliCostModel* self, uint16_t cmdcode) {
197 return self->cost_cmd_[cmdcode];
198 }
199
200 static BROTLI_INLINE float ZopfliCostModelGetDistanceCost(
201 const ZopfliCostModel* self, size_t distcode) {
202 return self->cost_dist_[distcode];
203 }
204
205 static BROTLI_INLINE float ZopfliCostModelGetLiteralCosts(
206 const ZopfliCostModel* self, size_t from, size_t to) {
207 return self->literal_costs_[to] - self->literal_costs_[from];
208 }
209
210 static BROTLI_INLINE float ZopfliCostModelGetMinCostCmd(
211 const ZopfliCostModel* self) {
212 return self->min_cost_cmd_;
213 }
214
215 static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
216 size_t max_distance,
217 const int* dist_cache) {
218 if (distance <= max_distance) {
219 size_t distance_plus_3 = distance + 3;
220 size_t offset0 = distance_plus_3 - (size_t)dist_cache[0];
221 size_t offset1 = distance_plus_3 - (size_t)dist_cache[1];
222 if (distance == (size_t)dist_cache[0]) {
223 return 0;
224 } else if (distance == (size_t)dist_cache[1]) {
225 return 1;
226 } else if (offset0 < 7) {
227 return (0x9750468 >> (4 * offset0)) & 0xF;
228 } else if (offset1 < 7) {
229 return (0xFDB1ACE >> (4 * offset1)) & 0xF;
230 } else if (distance == (size_t)dist_cache[2]) {
231 return 2;
232 } else if (distance == (size_t)dist_cache[3]) {
233 return 3;
234 }
235 }
236 return distance + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
237 }
238
239 /* REQUIRES: len >= 2, start_pos <= pos */
240 /* REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity */
241 /* Maintains the "ZopfliNode array invariant". */
242 static BROTLI_INLINE void UpdateZopfliNode(ZopfliNode* nodes, size_t pos,
243 size_t start_pos, size_t len, size_t len_code, size_t dist,
244 size_t short_code, float cost) {
245 ZopfliNode* next = &nodes[pos + len];
246 next->length = (uint32_t)(len | ((len + 9u - len_code) << 24));
247 next->distance = (uint32_t)(dist | (short_code << 25));
248 next->insert_length = (uint32_t)(pos - start_pos);
249 next->u.cost = cost;
250 }
251
252 typedef struct PosData {
253 size_t pos;
254 int distance_cache[4];
255 float costdiff;
256 float cost;
257 } PosData;
258
259 /* Maintains the smallest 8 cost difference together with their positions */
260 typedef struct StartPosQueue {
261 PosData q_[8];
262 size_t idx_;
263 } StartPosQueue;
264
265 static BROTLI_INLINE void InitStartPosQueue(StartPosQueue* self) {
266 self->idx_ = 0;
267 }
268
269 static size_t StartPosQueueSize(const StartPosQueue* self) {
270 return BROTLI_MIN(size_t, self->idx_, 8);
271 }
272
273 static void StartPosQueuePush(StartPosQueue* self, const PosData* posdata) {
274 size_t offset = ~(self->idx_++) & 7;
275 size_t len = StartPosQueueSize(self);
276 size_t i;
277 PosData* q = self->q_;
278 q[offset] = *posdata;
279 /* Restore the sorted order. In the list of |len| items at most |len - 1|
280 adjacent element comparisons / swaps are required. */
281 for (i = 1; i < len; ++i) {
282 if (q[offset & 7].costdiff > q[(offset + 1) & 7].costdiff) {
283 BROTLI_SWAP(PosData, q, offset & 7, (offset + 1) & 7);
284 }
285 ++offset;
286 }
287 }
288
289 static const PosData* StartPosQueueAt(const StartPosQueue* self, size_t k) {
290 return &self->q_[(k - self->idx_) & 7];
291 }
292
293 /* Returns the minimum possible copy length that can improve the cost of any */
294 /* future position. */
295 static size_t ComputeMinimumCopyLength(const float start_cost,
296 const ZopfliNode* nodes,
297 const size_t num_bytes,
298 const size_t pos) {
299 /* Compute the minimum possible cost of reaching any future position. */
300 float min_cost = start_cost;
301 size_t len = 2;
302 size_t next_len_bucket = 4;
303 size_t next_len_offset = 10;
304 while (pos + len <= num_bytes && nodes[pos + len].u.cost <= min_cost) {
305 /* We already reached (pos + len) with no more cost than the minimum
306 possible cost of reaching anything from this pos, so there is no point in
307 looking for lengths <= len. */
308 ++len;
309 if (len == next_len_offset) {
310 /* We reached the next copy length code bucket, so we add one more
311 extra bit to the minimum cost. */
312 min_cost += 1.0f;
313 next_len_offset += next_len_bucket;
314 next_len_bucket *= 2;
315 }
316 }
317 return len;
318 }
319
320 /* REQUIRES: nodes[pos].cost < kInfinity
321 REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
322 static uint32_t ComputeDistanceShortcut(const size_t block_start,
323 const size_t pos,
324 const size_t max_backward,
325 const ZopfliNode* nodes) {
326 const size_t clen = ZopfliNodeCopyLength(&nodes[pos]);
327 const size_t ilen = nodes[pos].insert_length;
328 const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]);
329 /* Since |block_start + pos| is the end position of the command, the copy part
330 starts from |block_start + pos - clen|. Distances that are greater than
331 this or greater than |max_backward| are static dictionary references, and
332 do not update the last distances. Also distance code 0 (last distance)
333 does not update the last distances. */
334 if (pos == 0) {
335 return 0;
336 } else if (dist + clen <= block_start + pos &&
337 dist <= max_backward &&
338 ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
339 return (uint32_t)pos;
340 } else {
341 return nodes[pos - clen - ilen].u.shortcut;
342 }
343 }
344
345 /* Fills in dist_cache[0..3] with the last four distances (as defined by
346 Section 4. of the Spec) that would be used at (block_start + pos) if we
347 used the shortest path of commands from block_start, computed from
348 nodes[0..pos]. The last four distances at block_start are in
349 starting_dist_cach[0..3].
350 REQUIRES: nodes[pos].cost < kInfinity
351 REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
352 static void ComputeDistanceCache(const size_t pos,
353 const int* starting_dist_cache,
354 const ZopfliNode* nodes,
355 int* dist_cache) {
356 int idx = 0;
357 size_t p = nodes[pos].u.shortcut;
358 while (idx < 4 && p > 0) {
359 const size_t ilen = nodes[p].insert_length;
360 const size_t clen = ZopfliNodeCopyLength(&nodes[p]);
361 const size_t dist = ZopfliNodeCopyDistance(&nodes[p]);
362 dist_cache[idx++] = (int)dist;
363 /* Because of prerequisite, p >= clen + ilen >= 2. */
364 p = nodes[p - clen - ilen].u.shortcut;
365 }
366 for (; idx < 4; ++idx) {
367 dist_cache[idx] = *starting_dist_cache++;
368 }
369 }
370
371 /* Returns longest copy length. */
372 static size_t UpdateNodes(
373 const size_t num_bytes, const size_t block_start, const size_t pos,
374 const uint8_t* ringbuffer, const size_t ringbuffer_mask,
375 const BrotliEncoderParams* params, const size_t max_backward_limit,
376 const int* starting_dist_cache, const size_t num_matches,
377 const BackwardMatch* matches, const ZopfliCostModel* model,
378 StartPosQueue* queue, ZopfliNode* nodes) {
379 const size_t cur_ix = block_start + pos;
380 const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
381 const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
382 const size_t max_len = num_bytes - pos;
383 const size_t max_zopfli_len = MaxZopfliLen(params);
384 const size_t max_iters = MaxZopfliCandidates(params);
385 size_t min_len;
386 size_t result = 0;
387 size_t k;
388
389 {
390 /* Save cost, because ComputeDistanceCache invalidates it. */
391 float node_cost = nodes[pos].u.cost;
392 nodes[pos].u.shortcut = ComputeDistanceShortcut(
393 block_start, pos, max_backward_limit, nodes);
394 if (node_cost <= ZopfliCostModelGetLiteralCosts(model, 0, pos)) {
395 PosData posdata;
396 posdata.pos = pos;
397 posdata.cost = node_cost;
398 posdata.costdiff = node_cost -
399 ZopfliCostModelGetLiteralCosts(model, 0, pos);
400 ComputeDistanceCache(
401 pos, starting_dist_cache, nodes, posdata.distance_cache);
402 StartPosQueuePush(queue, &posdata);
403 }
404 }
405
406 {
407 const PosData* posdata = StartPosQueueAt(queue, 0);
408 float min_cost = (posdata->cost + ZopfliCostModelGetMinCostCmd(model) +
409 ZopfliCostModelGetLiteralCosts(model, posdata->pos, pos));
410 min_len = ComputeMinimumCopyLength(min_cost, nodes, num_bytes, pos);
411 }
412
413 /* Go over the command starting positions in order of increasing cost
414 difference. */
415 for (k = 0; k < max_iters && k < StartPosQueueSize(queue); ++k) {
416 const PosData* posdata = StartPosQueueAt(queue, k);
417 const size_t start = posdata->pos;
418 const uint16_t inscode = GetInsertLengthCode(pos - start);
419 const float start_costdiff = posdata->costdiff;
420 const float base_cost = start_costdiff + (float)GetInsertExtra(inscode) +
421 ZopfliCostModelGetLiteralCosts(model, 0, pos);
422
423 /* Look for last distance matches using the distance cache from this
424 starting position. */
425 size_t best_len = min_len - 1;
426 size_t j = 0;
427 for (; j < BROTLI_NUM_DISTANCE_SHORT_CODES && best_len < max_len; ++j) {
428 const size_t idx = kDistanceCacheIndex[j];
429 const size_t backward =
430 (size_t)(posdata->distance_cache[idx] + kDistanceCacheOffset[j]);
431 size_t prev_ix = cur_ix - backward;
432 if (prev_ix >= cur_ix) {
433 continue;
434 }
435 if (BROTLI_PREDICT_FALSE(backward > max_distance)) {
436 continue;
437 }
438 prev_ix &= ringbuffer_mask;
439
440 if (cur_ix_masked + best_len > ringbuffer_mask ||
441 prev_ix + best_len > ringbuffer_mask ||
442 ringbuffer[cur_ix_masked + best_len] !=
443 ringbuffer[prev_ix + best_len]) {
444 continue;
445 }
446 {
447 const size_t len =
448 FindMatchLengthWithLimit(&ringbuffer[prev_ix],
449 &ringbuffer[cur_ix_masked],
450 max_len);
451 const float dist_cost = base_cost +
452 ZopfliCostModelGetDistanceCost(model, j);
453 size_t l;
454 for (l = best_len + 1; l <= len; ++l) {
455 const uint16_t copycode = GetCopyLengthCode(l);
456 const uint16_t cmdcode =
457 CombineLengthCodes(inscode, copycode, j == 0);
458 const float cost = (cmdcode < 128 ? base_cost : dist_cost) +
459 (float)GetCopyExtra(copycode) +
460 ZopfliCostModelGetCommandCost(model, cmdcode);
461 if (cost < nodes[pos + l].u.cost) {
462 UpdateZopfliNode(nodes, pos, start, l, l, backward, j + 1, cost);
463 result = BROTLI_MAX(size_t, result, l);
464 }
465 best_len = l;
466 }
467 }
468 }
469
470 /* At higher iterations look only for new last distance matches, since
471 looking only for new command start positions with the same distances
472 does not help much. */
473 if (k >= 2) continue;
474
475 {
476 /* Loop through all possible copy lengths at this position. */
477 size_t len = min_len;
478 for (j = 0; j < num_matches; ++j) {
479 BackwardMatch match = matches[j];
480 size_t dist = match.distance;
481 BROTLI_BOOL is_dictionary_match = TO_BROTLI_BOOL(dist > max_distance);
482 /* We already tried all possible last distance matches, so we can use
483 normal distance code here. */
484 size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
485 uint16_t dist_symbol;
486 uint32_t distextra;
487 uint32_t distnumextra;
488 float dist_cost;
489 size_t max_match_len;
490 PrefixEncodeCopyDistance(dist_code, 0, 0, &dist_symbol, &distextra);
491 distnumextra = distextra >> 24;
492 dist_cost = base_cost + (float)distnumextra +
493 ZopfliCostModelGetDistanceCost(model, dist_symbol);
494
495 /* Try all copy lengths up until the maximum copy length corresponding
496 to this distance. If the distance refers to the static dictionary, or
497 the maximum length is long enough, try only one maximum length. */
498 max_match_len = BackwardMatchLength(&match);
499 if (len < max_match_len &&
500 (is_dictionary_match || max_match_len > max_zopfli_len)) {
501 len = max_match_len;
502 }
503 for (; len <= max_match_len; ++len) {
504 const size_t len_code =
505 is_dictionary_match ? BackwardMatchLengthCode(&match) : len;
506 const uint16_t copycode = GetCopyLengthCode(len_code);
507 const uint16_t cmdcode = CombineLengthCodes(inscode, copycode, 0);
508 const float cost = dist_cost + (float)GetCopyExtra(copycode) +
509 ZopfliCostModelGetCommandCost(model, cmdcode);
510 if (cost < nodes[pos + len].u.cost) {
511 UpdateZopfliNode(nodes, pos, start, len, len_code, dist, 0, cost);
512 result = BROTLI_MAX(size_t, result, len);
513 }
514 }
515 }
516 }
517 }
518 return result;
519 }
520
521 static size_t ComputeShortestPathFromNodes(size_t num_bytes,
522 ZopfliNode* nodes) {
523 size_t index = num_bytes;
524 size_t num_commands = 0;
525 while (nodes[index].insert_length == 0 && nodes[index].length == 1) --index;
526 nodes[index].u.next = BROTLI_UINT32_MAX;
527 while (index != 0) {
528 size_t len = ZopfliNodeCommandLength(&nodes[index]);
529 index -= len;
530 nodes[index].u.next = (uint32_t)len;
531 num_commands++;
532 }
533 return num_commands;
534 }
535
536 void BrotliZopfliCreateCommands(const size_t num_bytes,
537 const size_t block_start,
538 const size_t max_backward_limit,
539 const ZopfliNode* nodes,
540 int* dist_cache,
541 size_t* last_insert_len,
542 Command* commands,
543 size_t* num_literals) {
544 size_t pos = 0;
545 uint32_t offset = nodes[0].u.next;
546 size_t i;
547 for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
548 const ZopfliNode* next = &nodes[pos + offset];
549 size_t copy_length = ZopfliNodeCopyLength(next);
550 size_t insert_length = next->insert_length;
551 pos += insert_length;
552 offset = next->u.next;
553 if (i == 0) {
554 insert_length += *last_insert_len;
555 *last_insert_len = 0;
556 }
557 {
558 size_t distance = ZopfliNodeCopyDistance(next);
559 size_t len_code = ZopfliNodeLengthCode(next);
560 size_t max_distance =
561 BROTLI_MIN(size_t, block_start + pos, max_backward_limit);
562 BROTLI_BOOL is_dictionary = TO_BROTLI_BOOL(distance > max_distance);
563 size_t dist_code = ZopfliNodeDistanceCode(next);
564
565 InitCommand(
566 &commands[i], insert_length, copy_length, len_code, dist_code);
567
568 if (!is_dictionary && dist_code > 0) {
569 dist_cache[3] = dist_cache[2];
570 dist_cache[2] = dist_cache[1];
571 dist_cache[1] = dist_cache[0];
572 dist_cache[0] = (int)distance;
573 }
574 }
575
576 *num_literals += insert_length;
577 pos += copy_length;
578 }
579 *last_insert_len += num_bytes - pos;
580 }
581
582 static size_t ZopfliIterate(size_t num_bytes,
583 size_t position,
584 const uint8_t* ringbuffer,
585 size_t ringbuffer_mask,
586 const BrotliEncoderParams* params,
587 const size_t max_backward_limit,
588 const int* dist_cache,
589 const ZopfliCostModel* model,
590 const uint32_t* num_matches,
591 const BackwardMatch* matches,
592 ZopfliNode* nodes) {
593 const size_t max_zopfli_len = MaxZopfliLen(params);
594 StartPosQueue queue;
595 size_t cur_match_pos = 0;
596 size_t i;
597 size_t skip_to = 0;
598 nodes[0].length = 0;
599 nodes[0].u.cost = 0;
600 InitStartPosQueue(&queue);
601 for (i = 0; i + 3 < num_bytes; i++) {
602 if (i >= skip_to) {
603 size_t could_skip = UpdateNodes(num_bytes, position, i, ringbuffer,
604 ringbuffer_mask, params, max_backward_limit, dist_cache,
605 num_matches[i], &matches[cur_match_pos], model, &queue, nodes);
606 if (could_skip > BROTLI_LONG_COPY_QUICK_STEP) {
607 /* Previous copy was very long; no need to scan thoroughly. */
608 skip_to = i + could_skip;
609 InitStartPosQueue(&queue);
610 }
611 }
612 cur_match_pos += num_matches[i];
613 /* The zopflification can be too slow in case of very long lengths, so in
614 such case skip it all, it does not cost a lot of compression ratio. */
615 if (num_matches[i] == 1 &&
616 BackwardMatchLength(&matches[cur_match_pos - 1]) > max_zopfli_len) {
617 i += BackwardMatchLength(&matches[cur_match_pos - 1]) - 1;
618 InitStartPosQueue(&queue);
619 }
620 }
621 return ComputeShortestPathFromNodes(num_bytes, nodes);
622 }
623
624
625 size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
626 size_t num_bytes,
627 size_t position,
628 const uint8_t* ringbuffer,
629 size_t ringbuffer_mask,
630 const BrotliEncoderParams* params,
631 const size_t max_backward_limit,
632 const int* dist_cache,
633 H10* hasher,
634 ZopfliNode* nodes) {
635 const size_t max_zopfli_len = MaxZopfliLen(params);
636 ZopfliCostModel model;
637 StartPosQueue queue;
638 BackwardMatch matches[MAX_NUM_MATCHES_H10];
639 const size_t store_end = num_bytes >= StoreLookaheadH10() ?
640 position + num_bytes - StoreLookaheadH10() + 1 : position;
641 size_t i;
642 nodes[0].length = 0;
643 nodes[0].u.cost = 0;
644 InitZopfliCostModel(m, &model, num_bytes);
645 if (BROTLI_IS_OOM(m)) return 0;
646 ZopfliCostModelSetFromLiteralCosts(
647 &model, position, ringbuffer, ringbuffer_mask);
648 InitStartPosQueue(&queue);
649 for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
650 const size_t pos = position + i;
651 const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
652 size_t num_matches = FindAllMatchesH10(hasher, ringbuffer, ringbuffer_mask,
653 pos, num_bytes - i, max_distance, params, matches);
654 size_t could_skip;
655 if (num_matches > 0 &&
656 BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
657 matches[0] = matches[num_matches - 1];
658 num_matches = 1;
659 }
660 could_skip = UpdateNodes(num_bytes, position, i, ringbuffer,
661 ringbuffer_mask, params, max_backward_limit, dist_cache, num_matches,
662 matches, &model, &queue, nodes);
663 if (could_skip > BROTLI_LONG_COPY_QUICK_STEP) {
664 i += could_skip - 1;
665 StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
666 size_t, pos + could_skip - 1, store_end));
667 InitStartPosQueue(&queue);
668 continue;
669 }
670 if (num_matches == 1 && BackwardMatchLength(&matches[0]) > max_zopfli_len) {
671 /* Add the tail of the copy to the hasher. */
672 StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
673 size_t, pos + BackwardMatchLength(&matches[0]), store_end));
674 i += BackwardMatchLength(&matches[0]) - 1;
675 InitStartPosQueue(&queue);
676 }
677 }
678 CleanupZopfliCostModel(m, &model);
679 return ComputeShortestPathFromNodes(num_bytes, nodes);
680 }
681
682 #define EXPAND_CAT(a, b) CAT(a, b)
683 #define CAT(a, b) a ## b
684 #define FN(X) EXPAND_CAT(X, HASHER())
685
686 #define HASHER() H2
687 /* NOLINTNEXTLINE(build/include) */
688 #include "./backward_references_inc.h"
689 #undef HASHER
690
691 #define HASHER() H3
692 /* NOLINTNEXTLINE(build/include) */
693 #include "./backward_references_inc.h"
694 #undef HASHER
695
696 #define HASHER() H4
697 /* NOLINTNEXTLINE(build/include) */
698 #include "./backward_references_inc.h"
699 #undef HASHER
700
701 #define HASHER() H5
702 /* NOLINTNEXTLINE(build/include) */
703 #include "./backward_references_inc.h"
704 #undef HASHER
705
706 #define HASHER() H6
707 /* NOLINTNEXTLINE(build/include) */
708 #include "./backward_references_inc.h"
709 #undef HASHER
710
711 #define HASHER() H7
712 /* NOLINTNEXTLINE(build/include) */
713 #include "./backward_references_inc.h"
714 #undef HASHER
715
716 #define HASHER() H8
717 /* NOLINTNEXTLINE(build/include) */
718 #include "./backward_references_inc.h"
719 #undef HASHER
720
721 #define HASHER() H9
722 /* NOLINTNEXTLINE(build/include) */
723 #include "./backward_references_inc.h"
724 #undef HASHER
725
726 #define HASHER() H40
727 /* NOLINTNEXTLINE(build/include) */
728 #include "./backward_references_inc.h"
729 #undef HASHER
730
731 #define HASHER() H41
732 /* NOLINTNEXTLINE(build/include) */
733 #include "./backward_references_inc.h"
734 #undef HASHER
735
736 #define HASHER() H42
737 /* NOLINTNEXTLINE(build/include) */
738 #include "./backward_references_inc.h"
739 #undef HASHER
740
741 #undef FN
742 #undef CAT
743 #undef EXPAND_CAT
744
745 static BROTLI_NOINLINE void CreateZopfliBackwardReferences(
746 MemoryManager* m, size_t num_bytes, size_t position, BROTLI_BOOL is_last,
747 const uint8_t* ringbuffer, size_t ringbuffer_mask,
748 const BrotliEncoderParams* params, H10* hasher, int* dist_cache,
749 size_t* last_insert_len, Command* commands, size_t* num_commands,
750 size_t* num_literals) {
751 const size_t max_backward_limit = MaxBackwardLimit(params->lgwin);
752 ZopfliNode* nodes;
753 InitH10(m, hasher, ringbuffer, params, position, num_bytes, is_last);
754 if (BROTLI_IS_OOM(m)) return;
755 StitchToPreviousBlockH10(hasher, num_bytes, position,
756 ringbuffer, ringbuffer_mask);
757 nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
758 if (BROTLI_IS_OOM(m)) return;
759 BrotliInitZopfliNodes(nodes, num_bytes + 1);
760 *num_commands += BrotliZopfliComputeShortestPath(m, num_bytes, position,
761 ringbuffer, ringbuffer_mask, params, max_backward_limit,
762 dist_cache, hasher, nodes);
763 if (BROTLI_IS_OOM(m)) return;
764 BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit, nodes,
765 dist_cache, last_insert_len, commands, num_literals);
766 BROTLI_FREE(m, nodes);
767 }
768
769 static BROTLI_NOINLINE void CreateHqZopfliBackwardReferences(
770 MemoryManager* m, size_t num_bytes, size_t position, BROTLI_BOOL is_last,
771 const uint8_t* ringbuffer, size_t ringbuffer_mask,
772 const BrotliEncoderParams* params, H10* hasher, int* dist_cache,
773 size_t* last_insert_len, Command* commands, size_t* num_commands,
774 size_t* num_literals) {
775 const size_t max_backward_limit = MaxBackwardLimit(params->lgwin);
776 uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
777 size_t matches_size = 4 * num_bytes;
778 const size_t store_end = num_bytes >= StoreLookaheadH10() ?
779 position + num_bytes - StoreLookaheadH10() + 1 : position;
780 size_t cur_match_pos = 0;
781 size_t i;
782 size_t orig_num_literals;
783 size_t orig_last_insert_len;
784 int orig_dist_cache[4];
785 size_t orig_num_commands;
786 ZopfliCostModel model;
787 ZopfliNode* nodes;
788 BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
789 if (BROTLI_IS_OOM(m)) return;
790 InitH10(m, hasher, ringbuffer, params, position, num_bytes, is_last);
791 if (BROTLI_IS_OOM(m)) return;
792 StitchToPreviousBlockH10(hasher, num_bytes, position,
793 ringbuffer, ringbuffer_mask);
794 for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
795 const size_t pos = position + i;
796 size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
797 size_t max_length = num_bytes - i;
798 size_t num_found_matches;
799 size_t cur_match_end;
800 size_t j;
801 /* Ensure that we have enough free slots. */
802 BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
803 cur_match_pos + MAX_NUM_MATCHES_H10);
804 if (BROTLI_IS_OOM(m)) return;
805 num_found_matches = FindAllMatchesH10(hasher, ringbuffer, ringbuffer_mask,
806 pos, max_length, max_distance, params, &matches[cur_match_pos]);
807 cur_match_end = cur_match_pos + num_found_matches;
808 for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
809 assert(BackwardMatchLength(&matches[j]) <
810 BackwardMatchLength(&matches[j + 1]));
811 assert(matches[j].distance > max_distance ||
812 matches[j].distance <= matches[j + 1].distance);
813 }
814 num_matches[i] = (uint32_t)num_found_matches;
815 if (num_found_matches > 0) {
816 const size_t match_len = BackwardMatchLength(&matches[cur_match_end - 1]);
817 if (match_len > MAX_ZOPFLI_LEN_QUALITY_11) {
818 const size_t skip = match_len - 1;
819 matches[cur_match_pos++] = matches[cur_match_end - 1];
820 num_matches[i] = 1;
821 /* Add the tail of the copy to the hasher. */
822 StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1,
823 BROTLI_MIN(size_t, pos + match_len, store_end));
824 memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
825 i += skip;
826 } else {
827 cur_match_pos = cur_match_end;
828 }
829 }
830 }
831 orig_num_literals = *num_literals;
832 orig_last_insert_len = *last_insert_len;
833 memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
834 orig_num_commands = *num_commands;
835 nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
836 if (BROTLI_IS_OOM(m)) return;
837 InitZopfliCostModel(m, &model, num_bytes);
838 if (BROTLI_IS_OOM(m)) return;
839 for (i = 0; i < 2; i++) {
840 BrotliInitZopfliNodes(nodes, num_bytes + 1);
841 if (i == 0) {
842 ZopfliCostModelSetFromLiteralCosts(
843 &model, position, ringbuffer, ringbuffer_mask);
844 } else {
845 ZopfliCostModelSetFromCommands(&model, position, ringbuffer,
846 ringbuffer_mask, commands, *num_commands - orig_num_commands,
847 orig_last_insert_len);
848 }
849 *num_commands = orig_num_commands;
850 *num_literals = orig_num_literals;
851 *last_insert_len = orig_last_insert_len;
852 memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
853 *num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
854 ringbuffer_mask, params, max_backward_limit, dist_cache,
855 &model, num_matches, matches, nodes);
856 BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit,
857 nodes, dist_cache, last_insert_len, commands, num_literals);
858 }
859 CleanupZopfliCostModel(m, &model);
860 BROTLI_FREE(m, nodes);
861 BROTLI_FREE(m, matches);
862 BROTLI_FREE(m, num_matches);
863 }
864
865 void BrotliCreateBackwardReferences(MemoryManager* m,
866 size_t num_bytes,
867 size_t position,
868 BROTLI_BOOL is_last,
869 const uint8_t* ringbuffer,
870 size_t ringbuffer_mask,
871 const BrotliEncoderParams* params,
872 Hashers* hashers,
873 int* dist_cache,
874 size_t* last_insert_len,
875 Command* commands,
876 size_t* num_commands,
877 size_t* num_literals) {
878 if (params->quality == ZOPFLIFICATION_QUALITY) {
879 CreateZopfliBackwardReferences(
880 m, num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
881 params, hashers->h10, dist_cache,
882 last_insert_len, commands, num_commands, num_literals);
883 return;
884 } else if (params->quality == HQ_ZOPFLIFICATION_QUALITY) {
885 CreateHqZopfliBackwardReferences(
886 m, num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
887 params, hashers->h10, dist_cache,
888 last_insert_len, commands, num_commands, num_literals);
889 return;
890 }
891
892 switch (ChooseHasher(params)) {
893 #define CASE_(N) \
894 case N: \
895 CreateBackwardReferencesH ## N(m, num_bytes, position, is_last, \
896 ringbuffer, ringbuffer_mask, params, hashers->h ## N, dist_cache, \
897 last_insert_len, commands, num_commands, num_literals); \
898 break;
899 FOR_GENERIC_HASHERS(CASE_)
900 #undef CASE_
901 default:
902 break;
903 }
904 if (BROTLI_IS_OOM(m)) return;
905 }
906
907 #if defined(__cplusplus) || defined(c_plusplus)
908 } /* extern "C" */
909 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698