source: code/trunk/vendor/github.com/andybalholm/brotli/backward_references_hq.go@ 145

Last change on this file since 145 was 145, checked in by Izuru Yakumo, 22 months ago

Updated the Makefile and vendored depedencies

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 26.9 KB
Line 
1package brotli
2
3import "math"
4
5type zopfliNode struct {
6 length uint32
7 distance uint32
8 dcode_insert_length uint32
9 u struct {
10 cost float32
11 next uint32
12 shortcut uint32
13 }
14}
15
16const maxEffectiveDistanceAlphabetSize = 544
17
18const kInfinity float32 = 1.7e38 /* ~= 2 ^ 127 */
19
20var kDistanceCacheIndex = []uint32{0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}
21
22var kDistanceCacheOffset = []int{0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3}
23
24func initZopfliNodes(array []zopfliNode, length uint) {
25 var stub zopfliNode
26 var i uint
27 stub.length = 1
28 stub.distance = 0
29 stub.dcode_insert_length = 0
30 stub.u.cost = kInfinity
31 for i = 0; i < length; i++ {
32 array[i] = stub
33 }
34}
35
36func zopfliNodeCopyLength(self *zopfliNode) uint32 {
37 return self.length & 0x1FFFFFF
38}
39
40func zopfliNodeLengthCode(self *zopfliNode) uint32 {
41 var modifier uint32 = self.length >> 25
42 return zopfliNodeCopyLength(self) + 9 - modifier
43}
44
45func zopfliNodeCopyDistance(self *zopfliNode) uint32 {
46 return self.distance
47}
48
49func zopfliNodeDistanceCode(self *zopfliNode) uint32 {
50 var short_code uint32 = self.dcode_insert_length >> 27
51 if short_code == 0 {
52 return zopfliNodeCopyDistance(self) + numDistanceShortCodes - 1
53 } else {
54 return short_code - 1
55 }
56}
57
58func zopfliNodeCommandLength(self *zopfliNode) uint32 {
59 return zopfliNodeCopyLength(self) + (self.dcode_insert_length & 0x7FFFFFF)
60}
61
62/* Histogram based cost model for zopflification. */
63type zopfliCostModel struct {
64 cost_cmd_ [numCommandSymbols]float32
65 cost_dist_ []float32
66 distance_histogram_size uint32
67 literal_costs_ []float32
68 min_cost_cmd_ float32
69 num_bytes_ uint
70}
71
72func initZopfliCostModel(self *zopfliCostModel, dist *distanceParams, num_bytes uint) {
73 var distance_histogram_size uint32 = dist.alphabet_size
74 if distance_histogram_size > maxEffectiveDistanceAlphabetSize {
75 distance_histogram_size = maxEffectiveDistanceAlphabetSize
76 }
77
78 self.num_bytes_ = num_bytes
79 self.literal_costs_ = make([]float32, (num_bytes + 2))
80 self.cost_dist_ = make([]float32, (dist.alphabet_size))
81 self.distance_histogram_size = distance_histogram_size
82}
83
84func cleanupZopfliCostModel(self *zopfliCostModel) {
85 self.literal_costs_ = nil
86 self.cost_dist_ = nil
87}
88
89func setCost(histogram []uint32, histogram_size uint, literal_histogram bool, cost []float32) {
90 var sum uint = 0
91 var missing_symbol_sum uint
92 var log2sum float32
93 var missing_symbol_cost float32
94 var i uint
95 for i = 0; i < histogram_size; i++ {
96 sum += uint(histogram[i])
97 }
98
99 log2sum = float32(fastLog2(sum))
100 missing_symbol_sum = sum
101 if !literal_histogram {
102 for i = 0; i < histogram_size; i++ {
103 if histogram[i] == 0 {
104 missing_symbol_sum++
105 }
106 }
107 }
108
109 missing_symbol_cost = float32(fastLog2(missing_symbol_sum)) + 2
110 for i = 0; i < histogram_size; i++ {
111 if histogram[i] == 0 {
112 cost[i] = missing_symbol_cost
113 continue
114 }
115
116 /* Shannon bits for this symbol. */
117 cost[i] = log2sum - float32(fastLog2(uint(histogram[i])))
118
119 /* Cannot be coded with less than 1 bit */
120 if cost[i] < 1 {
121 cost[i] = 1
122 }
123 }
124}
125
126func zopfliCostModelSetFromCommands(self *zopfliCostModel, position uint, ringbuffer []byte, ringbuffer_mask uint, commands []command, last_insert_len uint) {
127 var histogram_literal [numLiteralSymbols]uint32
128 var histogram_cmd [numCommandSymbols]uint32
129 var histogram_dist [maxEffectiveDistanceAlphabetSize]uint32
130 var cost_literal [numLiteralSymbols]float32
131 var pos uint = position - last_insert_len
132 var min_cost_cmd float32 = kInfinity
133 var cost_cmd []float32 = self.cost_cmd_[:]
134 var literal_costs []float32
135
136 histogram_literal = [numLiteralSymbols]uint32{}
137 histogram_cmd = [numCommandSymbols]uint32{}
138 histogram_dist = [maxEffectiveDistanceAlphabetSize]uint32{}
139
140 for i := range commands {
141 var inslength uint = uint(commands[i].insert_len_)
142 var copylength uint = uint(commandCopyLen(&commands[i]))
143 var distcode uint = uint(commands[i].dist_prefix_) & 0x3FF
144 var cmdcode uint = uint(commands[i].cmd_prefix_)
145 var j uint
146
147 histogram_cmd[cmdcode]++
148 if cmdcode >= 128 {
149 histogram_dist[distcode]++
150 }
151
152 for j = 0; j < inslength; j++ {
153 histogram_literal[ringbuffer[(pos+j)&ringbuffer_mask]]++
154 }
155
156 pos += inslength + copylength
157 }
158
159 setCost(histogram_literal[:], numLiteralSymbols, true, cost_literal[:])
160 setCost(histogram_cmd[:], numCommandSymbols, false, cost_cmd)
161 setCost(histogram_dist[:], uint(self.distance_histogram_size), false, self.cost_dist_)
162
163 for i := 0; i < numCommandSymbols; i++ {
164 min_cost_cmd = brotli_min_float(min_cost_cmd, cost_cmd[i])
165 }
166
167 self.min_cost_cmd_ = min_cost_cmd
168 {
169 literal_costs = self.literal_costs_
170 var literal_carry float32 = 0.0
171 num_bytes := int(self.num_bytes_)
172 literal_costs[0] = 0.0
173 for i := 0; i < num_bytes; i++ {
174 literal_carry += cost_literal[ringbuffer[(position+uint(i))&ringbuffer_mask]]
175 literal_costs[i+1] = literal_costs[i] + literal_carry
176 literal_carry -= literal_costs[i+1] - literal_costs[i]
177 }
178 }
179}
180
181func zopfliCostModelSetFromLiteralCosts(self *zopfliCostModel, position uint, ringbuffer []byte, ringbuffer_mask uint) {
182 var literal_costs []float32 = self.literal_costs_
183 var literal_carry float32 = 0.0
184 var cost_dist []float32 = self.cost_dist_
185 var cost_cmd []float32 = self.cost_cmd_[:]
186 var num_bytes uint = self.num_bytes_
187 var i uint
188 estimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask, ringbuffer, literal_costs[1:])
189 literal_costs[0] = 0.0
190 for i = 0; i < num_bytes; i++ {
191 literal_carry += literal_costs[i+1]
192 literal_costs[i+1] = literal_costs[i] + literal_carry
193 literal_carry -= literal_costs[i+1] - literal_costs[i]
194 }
195
196 for i = 0; i < numCommandSymbols; i++ {
197 cost_cmd[i] = float32(fastLog2(uint(11 + uint32(i))))
198 }
199
200 for i = 0; uint32(i) < self.distance_histogram_size; i++ {
201 cost_dist[i] = float32(fastLog2(uint(20 + uint32(i))))
202 }
203
204 self.min_cost_cmd_ = float32(fastLog2(11))
205}
206
207func zopfliCostModelGetCommandCost(self *zopfliCostModel, cmdcode uint16) float32 {
208 return self.cost_cmd_[cmdcode]
209}
210
211func zopfliCostModelGetDistanceCost(self *zopfliCostModel, distcode uint) float32 {
212 return self.cost_dist_[distcode]
213}
214
215func zopfliCostModelGetLiteralCosts(self *zopfliCostModel, from uint, to uint) float32 {
216 return self.literal_costs_[to] - self.literal_costs_[from]
217}
218
219func zopfliCostModelGetMinCostCmd(self *zopfliCostModel) float32 {
220 return self.min_cost_cmd_
221}
222
223/* REQUIRES: len >= 2, start_pos <= pos */
224/* REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity */
225/* Maintains the "ZopfliNode array invariant". */
226func updateZopfliNode(nodes []zopfliNode, pos uint, start_pos uint, len uint, len_code uint, dist uint, short_code uint, cost float32) {
227 var next *zopfliNode = &nodes[pos+len]
228 next.length = uint32(len | (len+9-len_code)<<25)
229 next.distance = uint32(dist)
230 next.dcode_insert_length = uint32(short_code<<27 | (pos - start_pos))
231 next.u.cost = cost
232}
233
234type posData struct {
235 pos uint
236 distance_cache [4]int
237 costdiff float32
238 cost float32
239}
240
241/* Maintains the smallest 8 cost difference together with their positions */
242type startPosQueue struct {
243 q_ [8]posData
244 idx_ uint
245}
246
247func initStartPosQueue(self *startPosQueue) {
248 self.idx_ = 0
249}
250
251func startPosQueueSize(self *startPosQueue) uint {
252 return brotli_min_size_t(self.idx_, 8)
253}
254
255func startPosQueuePush(self *startPosQueue, posdata *posData) {
256 var offset uint = ^(self.idx_) & 7
257 self.idx_++
258 var len uint = startPosQueueSize(self)
259 var i uint
260 var q []posData = self.q_[:]
261 q[offset] = *posdata
262
263 /* Restore the sorted order. In the list of |len| items at most |len - 1|
264 adjacent element comparisons / swaps are required. */
265 for i = 1; i < len; i++ {
266 if q[offset&7].costdiff > q[(offset+1)&7].costdiff {
267 var tmp posData = q[offset&7]
268 q[offset&7] = q[(offset+1)&7]
269 q[(offset+1)&7] = tmp
270 }
271
272 offset++
273 }
274}
275
276func startPosQueueAt(self *startPosQueue, k uint) *posData {
277 return &self.q_[(k-self.idx_)&7]
278}
279
280/* Returns the minimum possible copy length that can improve the cost of any */
281/* future position. */
282func computeMinimumCopyLength(start_cost float32, nodes []zopfliNode, num_bytes uint, pos uint) uint {
283 var min_cost float32 = start_cost
284 var len uint = 2
285 var next_len_bucket uint = 4
286 /* Compute the minimum possible cost of reaching any future position. */
287
288 var next_len_offset uint = 10
289 for pos+len <= num_bytes && nodes[pos+len].u.cost <= min_cost {
290 /* We already reached (pos + len) with no more cost than the minimum
291 possible cost of reaching anything from this pos, so there is no point in
292 looking for lengths <= len. */
293 len++
294
295 if len == next_len_offset {
296 /* We reached the next copy length code bucket, so we add one more
297 extra bit to the minimum cost. */
298 min_cost += 1.0
299
300 next_len_offset += next_len_bucket
301 next_len_bucket *= 2
302 }
303 }
304
305 return uint(len)
306}
307
308/* REQUIRES: nodes[pos].cost < kInfinity
309 REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
310func computeDistanceShortcut(block_start uint, pos uint, max_backward_limit uint, gap uint, nodes []zopfliNode) uint32 {
311 var clen uint = uint(zopfliNodeCopyLength(&nodes[pos]))
312 var ilen uint = uint(nodes[pos].dcode_insert_length & 0x7FFFFFF)
313 var dist uint = uint(zopfliNodeCopyDistance(&nodes[pos]))
314
315 /* Since |block_start + pos| is the end position of the command, the copy part
316 starts from |block_start + pos - clen|. Distances that are greater than
317 this or greater than |max_backward_limit| + |gap| are static dictionary
318 references, and do not update the last distances.
319 Also distance code 0 (last distance) does not update the last distances. */
320 if pos == 0 {
321 return 0
322 } else if dist+clen <= block_start+pos+gap && dist <= max_backward_limit+gap && zopfliNodeDistanceCode(&nodes[pos]) > 0 {
323 return uint32(pos)
324 } else {
325 return nodes[pos-clen-ilen].u.shortcut
326 }
327}
328
329/* Fills in dist_cache[0..3] with the last four distances (as defined by
330 Section 4. of the Spec) that would be used at (block_start + pos) if we
331 used the shortest path of commands from block_start, computed from
332 nodes[0..pos]. The last four distances at block_start are in
333 starting_dist_cache[0..3].
334 REQUIRES: nodes[pos].cost < kInfinity
335 REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
336func computeDistanceCache(pos uint, starting_dist_cache []int, nodes []zopfliNode, dist_cache []int) {
337 var idx int = 0
338 var p uint = uint(nodes[pos].u.shortcut)
339 for idx < 4 && p > 0 {
340 var ilen uint = uint(nodes[p].dcode_insert_length & 0x7FFFFFF)
341 var clen uint = uint(zopfliNodeCopyLength(&nodes[p]))
342 var dist uint = uint(zopfliNodeCopyDistance(&nodes[p]))
343 dist_cache[idx] = int(dist)
344 idx++
345
346 /* Because of prerequisite, p >= clen + ilen >= 2. */
347 p = uint(nodes[p-clen-ilen].u.shortcut)
348 }
349
350 for ; idx < 4; idx++ {
351 dist_cache[idx] = starting_dist_cache[0]
352 starting_dist_cache = starting_dist_cache[1:]
353 }
354}
355
356/* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it
357 is eligible. */
358func evaluateNode(block_start uint, pos uint, max_backward_limit uint, gap uint, starting_dist_cache []int, model *zopfliCostModel, queue *startPosQueue, nodes []zopfliNode) {
359 /* Save cost, because ComputeDistanceCache invalidates it. */
360 var node_cost float32 = nodes[pos].u.cost
361 nodes[pos].u.shortcut = computeDistanceShortcut(block_start, pos, max_backward_limit, gap, nodes)
362 if node_cost <= zopfliCostModelGetLiteralCosts(model, 0, pos) {
363 var posdata posData
364 posdata.pos = pos
365 posdata.cost = node_cost
366 posdata.costdiff = node_cost - zopfliCostModelGetLiteralCosts(model, 0, pos)
367 computeDistanceCache(pos, starting_dist_cache, nodes, posdata.distance_cache[:])
368 startPosQueuePush(queue, &posdata)
369 }
370}
371
372/* Returns longest copy length. */
373func updateNodes(num_bytes uint, block_start uint, pos uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, max_backward_limit uint, starting_dist_cache []int, num_matches uint, matches []backwardMatch, model *zopfliCostModel, queue *startPosQueue, nodes []zopfliNode) uint {
374 var cur_ix uint = block_start + pos
375 var cur_ix_masked uint = cur_ix & ringbuffer_mask
376 var max_distance uint = brotli_min_size_t(cur_ix, max_backward_limit)
377 var max_len uint = num_bytes - pos
378 var max_zopfli_len uint = maxZopfliLen(params)
379 var max_iters uint = maxZopfliCandidates(params)
380 var min_len uint
381 var result uint = 0
382 var k uint
383 var gap uint = 0
384
385 evaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache, model, queue, nodes)
386 {
387 var posdata *posData = startPosQueueAt(queue, 0)
388 var min_cost float32 = (posdata.cost + zopfliCostModelGetMinCostCmd(model) + zopfliCostModelGetLiteralCosts(model, posdata.pos, pos))
389 min_len = computeMinimumCopyLength(min_cost, nodes, num_bytes, pos)
390 }
391
392 /* Go over the command starting positions in order of increasing cost
393 difference. */
394 for k = 0; k < max_iters && k < startPosQueueSize(queue); k++ {
395 var posdata *posData = startPosQueueAt(queue, k)
396 var start uint = posdata.pos
397 var inscode uint16 = getInsertLengthCode(pos - start)
398 var start_costdiff float32 = posdata.costdiff
399 var base_cost float32 = start_costdiff + float32(getInsertExtra(inscode)) + zopfliCostModelGetLiteralCosts(model, 0, pos)
400 var best_len uint = min_len - 1
401 var j uint = 0
402 /* Look for last distance matches using the distance cache from this
403 starting position. */
404 for ; j < numDistanceShortCodes && best_len < max_len; j++ {
405 var idx uint = uint(kDistanceCacheIndex[j])
406 var backward uint = uint(posdata.distance_cache[idx] + kDistanceCacheOffset[j])
407 var prev_ix uint = cur_ix - backward
408 var len uint = 0
409 var continuation byte = ringbuffer[cur_ix_masked+best_len]
410 if cur_ix_masked+best_len > ringbuffer_mask {
411 break
412 }
413
414 if backward > max_distance+gap {
415 /* Word dictionary -> ignore. */
416 continue
417 }
418
419 if backward <= max_distance {
420 /* Regular backward reference. */
421 if prev_ix >= cur_ix {
422 continue
423 }
424
425 prev_ix &= ringbuffer_mask
426 if prev_ix+best_len > ringbuffer_mask || continuation != ringbuffer[prev_ix+best_len] {
427 continue
428 }
429
430 len = findMatchLengthWithLimit(ringbuffer[prev_ix:], ringbuffer[cur_ix_masked:], max_len)
431 } else {
432 continue
433 }
434 {
435 var dist_cost float32 = base_cost + zopfliCostModelGetDistanceCost(model, j)
436 var l uint
437 for l = best_len + 1; l <= len; l++ {
438 var copycode uint16 = getCopyLengthCode(l)
439 var cmdcode uint16 = combineLengthCodes(inscode, copycode, j == 0)
440 var tmp float32
441 if cmdcode < 128 {
442 tmp = base_cost
443 } else {
444 tmp = dist_cost
445 }
446 var cost float32 = tmp + float32(getCopyExtra(copycode)) + zopfliCostModelGetCommandCost(model, cmdcode)
447 if cost < nodes[pos+l].u.cost {
448 updateZopfliNode(nodes, pos, start, l, l, backward, j+1, cost)
449 result = brotli_max_size_t(result, l)
450 }
451
452 best_len = l
453 }
454 }
455 }
456
457 /* At higher iterations look only for new last distance matches, since
458 looking only for new command start positions with the same distances
459 does not help much. */
460 if k >= 2 {
461 continue
462 }
463 {
464 /* Loop through all possible copy lengths at this position. */
465 var len uint = min_len
466 for j = 0; j < num_matches; j++ {
467 var match backwardMatch = matches[j]
468 var dist uint = uint(match.distance)
469 var is_dictionary_match bool = (dist > max_distance+gap)
470 var dist_code uint = dist + numDistanceShortCodes - 1
471 var dist_symbol uint16
472 var distextra uint32
473 var distnumextra uint32
474 var dist_cost float32
475 var max_match_len uint
476 /* We already tried all possible last distance matches, so we can use
477 normal distance code here. */
478 prefixEncodeCopyDistance(dist_code, uint(params.dist.num_direct_distance_codes), uint(params.dist.distance_postfix_bits), &dist_symbol, &distextra)
479
480 distnumextra = uint32(dist_symbol) >> 10
481 dist_cost = base_cost + float32(distnumextra) + zopfliCostModelGetDistanceCost(model, uint(dist_symbol)&0x3FF)
482
483 /* Try all copy lengths up until the maximum copy length corresponding
484 to this distance. If the distance refers to the static dictionary, or
485 the maximum length is long enough, try only one maximum length. */
486 max_match_len = backwardMatchLength(&match)
487
488 if len < max_match_len && (is_dictionary_match || max_match_len > max_zopfli_len) {
489 len = max_match_len
490 }
491
492 for ; len <= max_match_len; len++ {
493 var len_code uint
494 if is_dictionary_match {
495 len_code = backwardMatchLengthCode(&match)
496 } else {
497 len_code = len
498 }
499 var copycode uint16 = getCopyLengthCode(len_code)
500 var cmdcode uint16 = combineLengthCodes(inscode, copycode, false)
501 var cost float32 = dist_cost + float32(getCopyExtra(copycode)) + zopfliCostModelGetCommandCost(model, cmdcode)
502 if cost < nodes[pos+len].u.cost {
503 updateZopfliNode(nodes, pos, start, uint(len), len_code, dist, 0, cost)
504 if len > result {
505 result = len
506 }
507 }
508 }
509 }
510 }
511 }
512
513 return result
514}
515
516func computeShortestPathFromNodes(num_bytes uint, nodes []zopfliNode) uint {
517 var index uint = num_bytes
518 var num_commands uint = 0
519 for nodes[index].dcode_insert_length&0x7FFFFFF == 0 && nodes[index].length == 1 {
520 index--
521 }
522 nodes[index].u.next = math.MaxUint32
523 for index != 0 {
524 var len uint = uint(zopfliNodeCommandLength(&nodes[index]))
525 index -= uint(len)
526 nodes[index].u.next = uint32(len)
527 num_commands++
528 }
529
530 return num_commands
531}
532
533/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
534func zopfliCreateCommands(num_bytes uint, block_start uint, nodes []zopfliNode, dist_cache []int, last_insert_len *uint, params *encoderParams, commands *[]command, num_literals *uint) {
535 var max_backward_limit uint = maxBackwardLimit(params.lgwin)
536 var pos uint = 0
537 var offset uint32 = nodes[0].u.next
538 var i uint
539 var gap uint = 0
540 for i = 0; offset != math.MaxUint32; i++ {
541 var next *zopfliNode = &nodes[uint32(pos)+offset]
542 var copy_length uint = uint(zopfliNodeCopyLength(next))
543 var insert_length uint = uint(next.dcode_insert_length & 0x7FFFFFF)
544 pos += insert_length
545 offset = next.u.next
546 if i == 0 {
547 insert_length += *last_insert_len
548 *last_insert_len = 0
549 }
550 {
551 var distance uint = uint(zopfliNodeCopyDistance(next))
552 var len_code uint = uint(zopfliNodeLengthCode(next))
553 var max_distance uint = brotli_min_size_t(block_start+pos, max_backward_limit)
554 var is_dictionary bool = (distance > max_distance+gap)
555 var dist_code uint = uint(zopfliNodeDistanceCode(next))
556 *commands = append(*commands, makeCommand(&params.dist, insert_length, copy_length, int(len_code)-int(copy_length), dist_code))
557
558 if !is_dictionary && dist_code > 0 {
559 dist_cache[3] = dist_cache[2]
560 dist_cache[2] = dist_cache[1]
561 dist_cache[1] = dist_cache[0]
562 dist_cache[0] = int(distance)
563 }
564 }
565
566 *num_literals += insert_length
567 pos += copy_length
568 }
569
570 *last_insert_len += num_bytes - pos
571}
572
573func zopfliIterate(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, gap uint, dist_cache []int, model *zopfliCostModel, num_matches []uint32, matches []backwardMatch, nodes []zopfliNode) uint {
574 var max_backward_limit uint = maxBackwardLimit(params.lgwin)
575 var max_zopfli_len uint = maxZopfliLen(params)
576 var queue startPosQueue
577 var cur_match_pos uint = 0
578 var i uint
579 nodes[0].length = 0
580 nodes[0].u.cost = 0
581 initStartPosQueue(&queue)
582 for i = 0; i+3 < num_bytes; i++ {
583 var skip uint = updateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask, params, max_backward_limit, dist_cache, uint(num_matches[i]), matches[cur_match_pos:], model, &queue, nodes)
584 if skip < longCopyQuickStep {
585 skip = 0
586 }
587 cur_match_pos += uint(num_matches[i])
588 if num_matches[i] == 1 && backwardMatchLength(&matches[cur_match_pos-1]) > max_zopfli_len {
589 skip = brotli_max_size_t(backwardMatchLength(&matches[cur_match_pos-1]), skip)
590 }
591
592 if skip > 1 {
593 skip--
594 for skip != 0 {
595 i++
596 if i+3 >= num_bytes {
597 break
598 }
599 evaluateNode(position, i, max_backward_limit, gap, dist_cache, model, &queue, nodes)
600 cur_match_pos += uint(num_matches[i])
601 skip--
602 }
603 }
604 }
605
606 return computeShortestPathFromNodes(num_bytes, nodes)
607}
608
609/* Computes the shortest path of commands from position to at most
610 position + num_bytes.
611
612 On return, path->size() is the number of commands found and path[i] is the
613 length of the i-th command (copy length plus insert length).
614 Note that the sum of the lengths of all commands can be less than num_bytes.
615
616 On return, the nodes[0..num_bytes] array will have the following
617 "ZopfliNode array invariant":
618 For each i in [1..num_bytes], if nodes[i].cost < kInfinity, then
619 (1) nodes[i].copy_length() >= 2
620 (2) nodes[i].command_length() <= i and
621 (3) nodes[i - nodes[i].command_length()].cost < kInfinity
622
623 REQUIRES: nodes != nil and len(nodes) >= num_bytes + 1 */
624func zopfliComputeShortestPath(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, dist_cache []int, hasher *h10, nodes []zopfliNode) uint {
625 var max_backward_limit uint = maxBackwardLimit(params.lgwin)
626 var max_zopfli_len uint = maxZopfliLen(params)
627 var model zopfliCostModel
628 var queue startPosQueue
629 var matches [2 * (maxNumMatchesH10 + 64)]backwardMatch
630 var store_end uint
631 if num_bytes >= hasher.StoreLookahead() {
632 store_end = position + num_bytes - hasher.StoreLookahead() + 1
633 } else {
634 store_end = position
635 }
636 var i uint
637 var gap uint = 0
638 var lz_matches_offset uint = 0
639 nodes[0].length = 0
640 nodes[0].u.cost = 0
641 initZopfliCostModel(&model, &params.dist, num_bytes)
642 zopfliCostModelSetFromLiteralCosts(&model, position, ringbuffer, ringbuffer_mask)
643 initStartPosQueue(&queue)
644 for i = 0; i+hasher.HashTypeLength()-1 < num_bytes; i++ {
645 var pos uint = position + i
646 var max_distance uint = brotli_min_size_t(pos, max_backward_limit)
647 var skip uint
648 var num_matches uint
649 num_matches = findAllMatchesH10(hasher, &params.dictionary, ringbuffer, ringbuffer_mask, pos, num_bytes-i, max_distance, gap, params, matches[lz_matches_offset:])
650 if num_matches > 0 && backwardMatchLength(&matches[num_matches-1]) > max_zopfli_len {
651 matches[0] = matches[num_matches-1]
652 num_matches = 1
653 }
654
655 skip = updateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask, params, max_backward_limit, dist_cache, num_matches, matches[:], &model, &queue, nodes)
656 if skip < longCopyQuickStep {
657 skip = 0
658 }
659 if num_matches == 1 && backwardMatchLength(&matches[0]) > max_zopfli_len {
660 skip = brotli_max_size_t(backwardMatchLength(&matches[0]), skip)
661 }
662
663 if skip > 1 {
664 /* Add the tail of the copy to the hasher. */
665 hasher.StoreRange(ringbuffer, ringbuffer_mask, pos+1, brotli_min_size_t(pos+skip, store_end))
666
667 skip--
668 for skip != 0 {
669 i++
670 if i+hasher.HashTypeLength()-1 >= num_bytes {
671 break
672 }
673 evaluateNode(position, i, max_backward_limit, gap, dist_cache, &model, &queue, nodes)
674 skip--
675 }
676 }
677 }
678
679 cleanupZopfliCostModel(&model)
680 return computeShortestPathFromNodes(num_bytes, nodes)
681}
682
683func createZopfliBackwardReferences(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, hasher *h10, dist_cache []int, last_insert_len *uint, commands *[]command, num_literals *uint) {
684 var nodes []zopfliNode
685 nodes = make([]zopfliNode, (num_bytes + 1))
686 initZopfliNodes(nodes, num_bytes+1)
687 zopfliComputeShortestPath(num_bytes, position, ringbuffer, ringbuffer_mask, params, dist_cache, hasher, nodes)
688 zopfliCreateCommands(num_bytes, position, nodes, dist_cache, last_insert_len, params, commands, num_literals)
689 nodes = nil
690}
691
692func createHqZopfliBackwardReferences(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, hasher hasherHandle, dist_cache []int, last_insert_len *uint, commands *[]command, num_literals *uint) {
693 var max_backward_limit uint = maxBackwardLimit(params.lgwin)
694 var num_matches []uint32 = make([]uint32, num_bytes)
695 var matches_size uint = 4 * num_bytes
696 var store_end uint
697 if num_bytes >= hasher.StoreLookahead() {
698 store_end = position + num_bytes - hasher.StoreLookahead() + 1
699 } else {
700 store_end = position
701 }
702 var cur_match_pos uint = 0
703 var i uint
704 var orig_num_literals uint
705 var orig_last_insert_len uint
706 var orig_dist_cache [4]int
707 var orig_num_commands int
708 var model zopfliCostModel
709 var nodes []zopfliNode
710 var matches []backwardMatch = make([]backwardMatch, matches_size)
711 var gap uint = 0
712 var shadow_matches uint = 0
713 var new_array []backwardMatch
714 for i = 0; i+hasher.HashTypeLength()-1 < num_bytes; i++ {
715 var pos uint = position + i
716 var max_distance uint = brotli_min_size_t(pos, max_backward_limit)
717 var max_length uint = num_bytes - i
718 var num_found_matches uint
719 var cur_match_end uint
720 var j uint
721
722 /* Ensure that we have enough free slots. */
723 if matches_size < cur_match_pos+maxNumMatchesH10+shadow_matches {
724 var new_size uint = matches_size
725 if new_size == 0 {
726 new_size = cur_match_pos + maxNumMatchesH10 + shadow_matches
727 }
728
729 for new_size < cur_match_pos+maxNumMatchesH10+shadow_matches {
730 new_size *= 2
731 }
732
733 new_array = make([]backwardMatch, new_size)
734 if matches_size != 0 {
735 copy(new_array, matches[:matches_size])
736 }
737
738 matches = new_array
739 matches_size = new_size
740 }
741
742 num_found_matches = findAllMatchesH10(hasher.(*h10), &params.dictionary, ringbuffer, ringbuffer_mask, pos, max_length, max_distance, gap, params, matches[cur_match_pos+shadow_matches:])
743 cur_match_end = cur_match_pos + num_found_matches
744 for j = cur_match_pos; j+1 < cur_match_end; j++ {
745 assert(backwardMatchLength(&matches[j]) <= backwardMatchLength(&matches[j+1]))
746 }
747
748 num_matches[i] = uint32(num_found_matches)
749 if num_found_matches > 0 {
750 var match_len uint = backwardMatchLength(&matches[cur_match_end-1])
751 if match_len > maxZopfliLenQuality11 {
752 var skip uint = match_len - 1
753 matches[cur_match_pos] = matches[cur_match_end-1]
754 cur_match_pos++
755 num_matches[i] = 1
756
757 /* Add the tail of the copy to the hasher. */
758 hasher.StoreRange(ringbuffer, ringbuffer_mask, pos+1, brotli_min_size_t(pos+match_len, store_end))
759 var pos uint = i
760 for i := 0; i < int(skip); i++ {
761 num_matches[pos+1:][i] = 0
762 }
763 i += skip
764 } else {
765 cur_match_pos = cur_match_end
766 }
767 }
768 }
769
770 orig_num_literals = *num_literals
771 orig_last_insert_len = *last_insert_len
772 copy(orig_dist_cache[:], dist_cache[:4])
773 orig_num_commands = len(*commands)
774 nodes = make([]zopfliNode, (num_bytes + 1))
775 initZopfliCostModel(&model, &params.dist, num_bytes)
776 for i = 0; i < 2; i++ {
777 initZopfliNodes(nodes, num_bytes+1)
778 if i == 0 {
779 zopfliCostModelSetFromLiteralCosts(&model, position, ringbuffer, ringbuffer_mask)
780 } else {
781 zopfliCostModelSetFromCommands(&model, position, ringbuffer, ringbuffer_mask, (*commands)[orig_num_commands:], orig_last_insert_len)
782 }
783
784 *commands = (*commands)[:orig_num_commands]
785 *num_literals = orig_num_literals
786 *last_insert_len = orig_last_insert_len
787 copy(dist_cache, orig_dist_cache[:4])
788 zopfliIterate(num_bytes, position, ringbuffer, ringbuffer_mask, params, gap, dist_cache, &model, num_matches, matches, nodes)
789 zopfliCreateCommands(num_bytes, position, nodes, dist_cache, last_insert_len, params, commands, num_literals)
790 }
791
792 cleanupZopfliCostModel(&model)
793 nodes = nil
794 matches = nil
795 num_matches = nil
796}
Note: See TracBrowser for help on using the repository browser.