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

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

Issue 2537133002: Update brotli to v1.0.0-snapshot. (Closed)
Patch Set: Fixed typo 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_cache[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 /* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it
372 is eligible. */
373 static void EvaluateNode(
374 const size_t block_start, const size_t pos, const size_t max_backward_limit,
375 const int* starting_dist_cache, const ZopfliCostModel* model,
376 StartPosQueue* queue, ZopfliNode* nodes) {
377 /* Save cost, because ComputeDistanceCache invalidates it. */
378 float node_cost = nodes[pos].u.cost;
379 nodes[pos].u.shortcut = ComputeDistanceShortcut(
380 block_start, pos, max_backward_limit, nodes);
381 if (node_cost <= ZopfliCostModelGetLiteralCosts(model, 0, pos)) {
382 PosData posdata;
383 posdata.pos = pos;
384 posdata.cost = node_cost;
385 posdata.costdiff = node_cost -
386 ZopfliCostModelGetLiteralCosts(model, 0, pos);
387 ComputeDistanceCache(
388 pos, starting_dist_cache, nodes, posdata.distance_cache);
389 StartPosQueuePush(queue, &posdata);
390 }
391 }
392
393 /* Returns longest copy length. */
394 static size_t UpdateNodes(
395 const size_t num_bytes, const size_t block_start, const size_t pos,
396 const uint8_t* ringbuffer, const size_t ringbuffer_mask,
397 const BrotliEncoderParams* params, const size_t max_backward_limit,
398 const int* starting_dist_cache, const size_t num_matches,
399 const BackwardMatch* matches, const ZopfliCostModel* model,
400 StartPosQueue* queue, ZopfliNode* nodes) {
401 const size_t cur_ix = block_start + pos;
402 const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
403 const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
404 const size_t max_len = num_bytes - pos;
405 const size_t max_zopfli_len = MaxZopfliLen(params);
406 const size_t max_iters = MaxZopfliCandidates(params);
407 size_t min_len;
408 size_t result = 0;
409 size_t k;
410
411 EvaluateNode(block_start, pos, max_backward_limit, starting_dist_cache, model,
412 queue, nodes);
413
414 {
415 const PosData* posdata = StartPosQueueAt(queue, 0);
416 float min_cost = (posdata->cost + ZopfliCostModelGetMinCostCmd(model) +
417 ZopfliCostModelGetLiteralCosts(model, posdata->pos, pos));
418 min_len = ComputeMinimumCopyLength(min_cost, nodes, num_bytes, pos);
419 }
420
421 /* Go over the command starting positions in order of increasing cost
422 difference. */
423 for (k = 0; k < max_iters && k < StartPosQueueSize(queue); ++k) {
424 const PosData* posdata = StartPosQueueAt(queue, k);
425 const size_t start = posdata->pos;
426 const uint16_t inscode = GetInsertLengthCode(pos - start);
427 const float start_costdiff = posdata->costdiff;
428 const float base_cost = start_costdiff + (float)GetInsertExtra(inscode) +
429 ZopfliCostModelGetLiteralCosts(model, 0, pos);
430
431 /* Look for last distance matches using the distance cache from this
432 starting position. */
433 size_t best_len = min_len - 1;
434 size_t j = 0;
435 for (; j < BROTLI_NUM_DISTANCE_SHORT_CODES && best_len < max_len; ++j) {
436 const size_t idx = kDistanceCacheIndex[j];
437 const size_t backward =
438 (size_t)(posdata->distance_cache[idx] + kDistanceCacheOffset[j]);
439 size_t prev_ix = cur_ix - backward;
440 if (prev_ix >= cur_ix) {
441 continue;
442 }
443 if (BROTLI_PREDICT_FALSE(backward > max_distance)) {
444 continue;
445 }
446 prev_ix &= ringbuffer_mask;
447
448 if (cur_ix_masked + best_len > ringbuffer_mask ||
449 prev_ix + best_len > ringbuffer_mask ||
450 ringbuffer[cur_ix_masked + best_len] !=
451 ringbuffer[prev_ix + best_len]) {
452 continue;
453 }
454 {
455 const size_t len =
456 FindMatchLengthWithLimit(&ringbuffer[prev_ix],
457 &ringbuffer[cur_ix_masked],
458 max_len);
459 const float dist_cost = base_cost +
460 ZopfliCostModelGetDistanceCost(model, j);
461 size_t l;
462 for (l = best_len + 1; l <= len; ++l) {
463 const uint16_t copycode = GetCopyLengthCode(l);
464 const uint16_t cmdcode =
465 CombineLengthCodes(inscode, copycode, j == 0);
466 const float cost = (cmdcode < 128 ? base_cost : dist_cost) +
467 (float)GetCopyExtra(copycode) +
468 ZopfliCostModelGetCommandCost(model, cmdcode);
469 if (cost < nodes[pos + l].u.cost) {
470 UpdateZopfliNode(nodes, pos, start, l, l, backward, j + 1, cost);
471 result = BROTLI_MAX(size_t, result, l);
472 }
473 best_len = l;
474 }
475 }
476 }
477
478 /* At higher iterations look only for new last distance matches, since
479 looking only for new command start positions with the same distances
480 does not help much. */
481 if (k >= 2) continue;
482
483 {
484 /* Loop through all possible copy lengths at this position. */
485 size_t len = min_len;
486 for (j = 0; j < num_matches; ++j) {
487 BackwardMatch match = matches[j];
488 size_t dist = match.distance;
489 BROTLI_BOOL is_dictionary_match = TO_BROTLI_BOOL(dist > max_distance);
490 /* We already tried all possible last distance matches, so we can use
491 normal distance code here. */
492 size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
493 uint16_t dist_symbol;
494 uint32_t distextra;
495 uint32_t distnumextra;
496 float dist_cost;
497 size_t max_match_len;
498 PrefixEncodeCopyDistance(dist_code, 0, 0, &dist_symbol, &distextra);
499 distnumextra = distextra >> 24;
500 dist_cost = base_cost + (float)distnumextra +
501 ZopfliCostModelGetDistanceCost(model, dist_symbol);
502
503 /* Try all copy lengths up until the maximum copy length corresponding
504 to this distance. If the distance refers to the static dictionary, or
505 the maximum length is long enough, try only one maximum length. */
506 max_match_len = BackwardMatchLength(&match);
507 if (len < max_match_len &&
508 (is_dictionary_match || max_match_len > max_zopfli_len)) {
509 len = max_match_len;
510 }
511 for (; len <= max_match_len; ++len) {
512 const size_t len_code =
513 is_dictionary_match ? BackwardMatchLengthCode(&match) : len;
514 const uint16_t copycode = GetCopyLengthCode(len_code);
515 const uint16_t cmdcode = CombineLengthCodes(inscode, copycode, 0);
516 const float cost = dist_cost + (float)GetCopyExtra(copycode) +
517 ZopfliCostModelGetCommandCost(model, cmdcode);
518 if (cost < nodes[pos + len].u.cost) {
519 UpdateZopfliNode(nodes, pos, start, len, len_code, dist, 0, cost);
520 result = BROTLI_MAX(size_t, result, len);
521 }
522 }
523 }
524 }
525 }
526 return result;
527 }
528
529 static size_t ComputeShortestPathFromNodes(size_t num_bytes,
530 ZopfliNode* nodes) {
531 size_t index = num_bytes;
532 size_t num_commands = 0;
533 while (nodes[index].insert_length == 0 && nodes[index].length == 1) --index;
534 nodes[index].u.next = BROTLI_UINT32_MAX;
535 while (index != 0) {
536 size_t len = ZopfliNodeCommandLength(&nodes[index]);
537 index -= len;
538 nodes[index].u.next = (uint32_t)len;
539 num_commands++;
540 }
541 return num_commands;
542 }
543
544 void BrotliZopfliCreateCommands(const size_t num_bytes,
545 const size_t block_start,
546 const size_t max_backward_limit,
547 const ZopfliNode* nodes,
548 int* dist_cache,
549 size_t* last_insert_len,
550 Command* commands,
551 size_t* num_literals) {
552 size_t pos = 0;
553 uint32_t offset = nodes[0].u.next;
554 size_t i;
555 for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
556 const ZopfliNode* next = &nodes[pos + offset];
557 size_t copy_length = ZopfliNodeCopyLength(next);
558 size_t insert_length = next->insert_length;
559 pos += insert_length;
560 offset = next->u.next;
561 if (i == 0) {
562 insert_length += *last_insert_len;
563 *last_insert_len = 0;
564 }
565 {
566 size_t distance = ZopfliNodeCopyDistance(next);
567 size_t len_code = ZopfliNodeLengthCode(next);
568 size_t max_distance =
569 BROTLI_MIN(size_t, block_start + pos, max_backward_limit);
570 BROTLI_BOOL is_dictionary = TO_BROTLI_BOOL(distance > max_distance);
571 size_t dist_code = ZopfliNodeDistanceCode(next);
572
573 InitCommand(
574 &commands[i], insert_length, copy_length, len_code, dist_code);
575
576 if (!is_dictionary && dist_code > 0) {
577 dist_cache[3] = dist_cache[2];
578 dist_cache[2] = dist_cache[1];
579 dist_cache[1] = dist_cache[0];
580 dist_cache[0] = (int)distance;
581 }
582 }
583
584 *num_literals += insert_length;
585 pos += copy_length;
586 }
587 *last_insert_len += num_bytes - pos;
588 }
589
590 static size_t ZopfliIterate(size_t num_bytes,
591 size_t position,
592 const uint8_t* ringbuffer,
593 size_t ringbuffer_mask,
594 const BrotliEncoderParams* params,
595 const size_t max_backward_limit,
596 const int* dist_cache,
597 const ZopfliCostModel* model,
598 const uint32_t* num_matches,
599 const BackwardMatch* matches,
600 ZopfliNode* nodes) {
601 const size_t max_zopfli_len = MaxZopfliLen(params);
602 StartPosQueue queue;
603 size_t cur_match_pos = 0;
604 size_t i;
605 nodes[0].length = 0;
606 nodes[0].u.cost = 0;
607 InitStartPosQueue(&queue);
608 for (i = 0; i + 3 < num_bytes; i++) {
609 size_t skip = UpdateNodes(num_bytes, position, i, ringbuffer,
610 ringbuffer_mask, params, max_backward_limit, dist_cache,
611 num_matches[i], &matches[cur_match_pos], model, &queue, nodes);
612 if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
613 cur_match_pos += num_matches[i];
614 if (num_matches[i] == 1 &&
615 BackwardMatchLength(&matches[cur_match_pos - 1]) > max_zopfli_len) {
616 skip = BROTLI_MAX(size_t,
617 BackwardMatchLength(&matches[cur_match_pos - 1]), skip);
618 }
619 if (skip > 1) {
620 skip--;
621 while (skip) {
622 i++;
623 if (i + 3 >= num_bytes) break;
624 EvaluateNode(
625 position, i, max_backward_limit, dist_cache, model, &queue, nodes);
626 cur_match_pos += num_matches[i];
627 skip--;
628 }
629 }
630 }
631 return ComputeShortestPathFromNodes(num_bytes, nodes);
632 }
633
634
635 size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
636 size_t num_bytes,
637 size_t position,
638 const uint8_t* ringbuffer,
639 size_t ringbuffer_mask,
640 const BrotliEncoderParams* params,
641 const size_t max_backward_limit,
642 const int* dist_cache,
643 H10* hasher,
644 ZopfliNode* nodes) {
645 const size_t max_zopfli_len = MaxZopfliLen(params);
646 ZopfliCostModel model;
647 StartPosQueue queue;
648 BackwardMatch matches[MAX_NUM_MATCHES_H10];
649 const size_t store_end = num_bytes >= StoreLookaheadH10() ?
650 position + num_bytes - StoreLookaheadH10() + 1 : position;
651 size_t i;
652 nodes[0].length = 0;
653 nodes[0].u.cost = 0;
654 InitZopfliCostModel(m, &model, num_bytes);
655 if (BROTLI_IS_OOM(m)) return 0;
656 ZopfliCostModelSetFromLiteralCosts(
657 &model, position, ringbuffer, ringbuffer_mask);
658 InitStartPosQueue(&queue);
659 for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
660 const size_t pos = position + i;
661 const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
662 size_t num_matches = FindAllMatchesH10(hasher, ringbuffer, ringbuffer_mask,
663 pos, num_bytes - i, max_distance, params, matches);
664 size_t skip;
665 if (num_matches > 0 &&
666 BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
667 matches[0] = matches[num_matches - 1];
668 num_matches = 1;
669 }
670 skip = UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask,
671 params, max_backward_limit, dist_cache, num_matches, matches, &model,
672 &queue, nodes);
673 if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
674 if (num_matches == 1 && BackwardMatchLength(&matches[0]) > max_zopfli_len) {
675 skip = BROTLI_MAX(size_t, BackwardMatchLength(&matches[0]), skip);
676 }
677 if (skip > 1) {
678 /* Add the tail of the copy to the hasher. */
679 StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
680 size_t, pos + skip, store_end));
681 skip--;
682 while (skip) {
683 i++;
684 if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
685 EvaluateNode(
686 position, i, max_backward_limit, dist_cache, &model, &queue, nodes);
687 skip--;
688 }
689 }
690 }
691 CleanupZopfliCostModel(m, &model);
692 return ComputeShortestPathFromNodes(num_bytes, nodes);
693 }
694
695 #define EXPAND_CAT(a, b) CAT(a, b)
696 #define CAT(a, b) a ## b
697 #define FN(X) EXPAND_CAT(X, HASHER())
698
699 #define HASHER() H2
700 /* NOLINTNEXTLINE(build/include) */
701 #include "./backward_references_inc.h"
702 #undef HASHER
703
704 #define HASHER() H3
705 /* NOLINTNEXTLINE(build/include) */
706 #include "./backward_references_inc.h"
707 #undef HASHER
708
709 #define HASHER() H4
710 /* NOLINTNEXTLINE(build/include) */
711 #include "./backward_references_inc.h"
712 #undef HASHER
713
714 #define HASHER() H5
715 /* NOLINTNEXTLINE(build/include) */
716 #include "./backward_references_inc.h"
717 #undef HASHER
718
719 #define HASHER() H6
720 /* NOLINTNEXTLINE(build/include) */
721 #include "./backward_references_inc.h"
722 #undef HASHER
723
724 #define HASHER() H7
725 /* NOLINTNEXTLINE(build/include) */
726 #include "./backward_references_inc.h"
727 #undef HASHER
728
729 #define HASHER() H8
730 /* NOLINTNEXTLINE(build/include) */
731 #include "./backward_references_inc.h"
732 #undef HASHER
733
734 #define HASHER() H9
735 /* NOLINTNEXTLINE(build/include) */
736 #include "./backward_references_inc.h"
737 #undef HASHER
738
739 #define HASHER() H40
740 /* NOLINTNEXTLINE(build/include) */
741 #include "./backward_references_inc.h"
742 #undef HASHER
743
744 #define HASHER() H41
745 /* NOLINTNEXTLINE(build/include) */
746 #include "./backward_references_inc.h"
747 #undef HASHER
748
749 #define HASHER() H42
750 /* NOLINTNEXTLINE(build/include) */
751 #include "./backward_references_inc.h"
752 #undef HASHER
753
754 #undef FN
755 #undef CAT
756 #undef EXPAND_CAT
757
758 static BROTLI_NOINLINE void CreateZopfliBackwardReferences(
759 MemoryManager* m, size_t num_bytes, size_t position, BROTLI_BOOL is_last,
760 const uint8_t* ringbuffer, size_t ringbuffer_mask,
761 const BrotliEncoderParams* params, H10* hasher, int* dist_cache,
762 size_t* last_insert_len, Command* commands, size_t* num_commands,
763 size_t* num_literals) {
764 const size_t max_backward_limit = MaxBackwardLimit(params->lgwin);
765 ZopfliNode* nodes;
766 InitH10(m, hasher, ringbuffer, params, position, num_bytes, is_last);
767 if (BROTLI_IS_OOM(m)) return;
768 StitchToPreviousBlockH10(hasher, num_bytes, position,
769 ringbuffer, ringbuffer_mask);
770 nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
771 if (BROTLI_IS_OOM(m)) return;
772 BrotliInitZopfliNodes(nodes, num_bytes + 1);
773 *num_commands += BrotliZopfliComputeShortestPath(m, num_bytes, position,
774 ringbuffer, ringbuffer_mask, params, max_backward_limit,
775 dist_cache, hasher, nodes);
776 if (BROTLI_IS_OOM(m)) return;
777 BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit, nodes,
778 dist_cache, last_insert_len, commands, num_literals);
779 BROTLI_FREE(m, nodes);
780 }
781
782 static BROTLI_NOINLINE void CreateHqZopfliBackwardReferences(
783 MemoryManager* m, size_t num_bytes, size_t position, BROTLI_BOOL is_last,
784 const uint8_t* ringbuffer, size_t ringbuffer_mask,
785 const BrotliEncoderParams* params, H10* hasher, int* dist_cache,
786 size_t* last_insert_len, Command* commands, size_t* num_commands,
787 size_t* num_literals) {
788 const size_t max_backward_limit = MaxBackwardLimit(params->lgwin);
789 uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
790 size_t matches_size = 4 * num_bytes;
791 const size_t store_end = num_bytes >= StoreLookaheadH10() ?
792 position + num_bytes - StoreLookaheadH10() + 1 : position;
793 size_t cur_match_pos = 0;
794 size_t i;
795 size_t orig_num_literals;
796 size_t orig_last_insert_len;
797 int orig_dist_cache[4];
798 size_t orig_num_commands;
799 ZopfliCostModel model;
800 ZopfliNode* nodes;
801 BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
802 if (BROTLI_IS_OOM(m)) return;
803 InitH10(m, hasher, ringbuffer, params, position, num_bytes, is_last);
804 if (BROTLI_IS_OOM(m)) return;
805 StitchToPreviousBlockH10(hasher, num_bytes, position,
806 ringbuffer, ringbuffer_mask);
807 for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
808 const size_t pos = position + i;
809 size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
810 size_t max_length = num_bytes - i;
811 size_t num_found_matches;
812 size_t cur_match_end;
813 size_t j;
814 /* Ensure that we have enough free slots. */
815 BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
816 cur_match_pos + MAX_NUM_MATCHES_H10);
817 if (BROTLI_IS_OOM(m)) return;
818 num_found_matches = FindAllMatchesH10(hasher, ringbuffer, ringbuffer_mask,
819 pos, max_length, max_distance, params, &matches[cur_match_pos]);
820 cur_match_end = cur_match_pos + num_found_matches;
821 for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
822 assert(BackwardMatchLength(&matches[j]) <
823 BackwardMatchLength(&matches[j + 1]));
824 assert(matches[j].distance > max_distance ||
825 matches[j].distance <= matches[j + 1].distance);
826 }
827 num_matches[i] = (uint32_t)num_found_matches;
828 if (num_found_matches > 0) {
829 const size_t match_len = BackwardMatchLength(&matches[cur_match_end - 1]);
830 if (match_len > MAX_ZOPFLI_LEN_QUALITY_11) {
831 const size_t skip = match_len - 1;
832 matches[cur_match_pos++] = matches[cur_match_end - 1];
833 num_matches[i] = 1;
834 /* Add the tail of the copy to the hasher. */
835 StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1,
836 BROTLI_MIN(size_t, pos + match_len, store_end));
837 memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
838 i += skip;
839 } else {
840 cur_match_pos = cur_match_end;
841 }
842 }
843 }
844 orig_num_literals = *num_literals;
845 orig_last_insert_len = *last_insert_len;
846 memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
847 orig_num_commands = *num_commands;
848 nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
849 if (BROTLI_IS_OOM(m)) return;
850 InitZopfliCostModel(m, &model, num_bytes);
851 if (BROTLI_IS_OOM(m)) return;
852 for (i = 0; i < 2; i++) {
853 BrotliInitZopfliNodes(nodes, num_bytes + 1);
854 if (i == 0) {
855 ZopfliCostModelSetFromLiteralCosts(
856 &model, position, ringbuffer, ringbuffer_mask);
857 } else {
858 ZopfliCostModelSetFromCommands(&model, position, ringbuffer,
859 ringbuffer_mask, commands, *num_commands - orig_num_commands,
860 orig_last_insert_len);
861 }
862 *num_commands = orig_num_commands;
863 *num_literals = orig_num_literals;
864 *last_insert_len = orig_last_insert_len;
865 memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
866 *num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
867 ringbuffer_mask, params, max_backward_limit, dist_cache,
868 &model, num_matches, matches, nodes);
869 BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit,
870 nodes, dist_cache, last_insert_len, commands, num_literals);
871 }
872 CleanupZopfliCostModel(m, &model);
873 BROTLI_FREE(m, nodes);
874 BROTLI_FREE(m, matches);
875 BROTLI_FREE(m, num_matches);
876 }
877
878 void BrotliCreateBackwardReferences(MemoryManager* m,
879 size_t num_bytes,
880 size_t position,
881 BROTLI_BOOL is_last,
882 const uint8_t* ringbuffer,
883 size_t ringbuffer_mask,
884 const BrotliEncoderParams* params,
885 Hashers* hashers,
886 int* dist_cache,
887 size_t* last_insert_len,
888 Command* commands,
889 size_t* num_commands,
890 size_t* num_literals) {
891 if (params->quality == ZOPFLIFICATION_QUALITY) {
892 CreateZopfliBackwardReferences(
893 m, num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
894 params, hashers->h10, dist_cache,
895 last_insert_len, commands, num_commands, num_literals);
896 return;
897 } else if (params->quality == HQ_ZOPFLIFICATION_QUALITY) {
898 CreateHqZopfliBackwardReferences(
899 m, num_bytes, position, is_last, ringbuffer, ringbuffer_mask,
900 params, hashers->h10, dist_cache,
901 last_insert_len, commands, num_commands, num_literals);
902 return;
903 }
904
905 switch (ChooseHasher(params)) {
906 #define CASE_(N) \
907 case N: \
908 CreateBackwardReferencesH ## N(m, num_bytes, position, is_last, \
909 ringbuffer, ringbuffer_mask, params, hashers->h ## N, dist_cache, \
910 last_insert_len, commands, num_commands, num_literals); \
911 break;
912 FOR_GENERIC_HASHERS(CASE_)
913 #undef CASE_
914 default:
915 break;
916 }
917 if (BROTLI_IS_OOM(m)) return;
918 }
919
920 #if defined(__cplusplus) || defined(c_plusplus)
921 } /* extern "C" */
922 #endif
OLDNEW
« no previous file with comments | « third_party/brotli/enc/backward_references.h ('k') | third_party/brotli/enc/backward_references.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698