github.com/andybalholm/brotli@v1.0.6/compress_fragment.go (about) 1 package brotli 2 3 import "encoding/binary" 4 5 /* Copyright 2015 Google Inc. All Rights Reserved. 6 7 Distributed under MIT license. 8 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 9 */ 10 11 /* Function for fast encoding of an input fragment, independently from the input 12 history. This function uses one-pass processing: when we find a backward 13 match, we immediately emit the corresponding command and literal codes to 14 the bit stream. 15 16 Adapted from the CompressFragment() function in 17 https://github.com/google/snappy/blob/master/snappy.cc */ 18 19 const maxDistance_compress_fragment = 262128 20 21 func hash5(p []byte, shift uint) uint32 { 22 var h uint64 = (binary.LittleEndian.Uint64(p) << 24) * uint64(kHashMul32) 23 return uint32(h >> shift) 24 } 25 26 func hashBytesAtOffset5(v uint64, offset int, shift uint) uint32 { 27 assert(offset >= 0) 28 assert(offset <= 3) 29 { 30 var h uint64 = ((v >> uint(8*offset)) << 24) * uint64(kHashMul32) 31 return uint32(h >> shift) 32 } 33 } 34 35 func isMatch5(p1 []byte, p2 []byte) bool { 36 return binary.LittleEndian.Uint32(p1) == binary.LittleEndian.Uint32(p2) && 37 p1[4] == p2[4] 38 } 39 40 /* Builds a literal prefix code into "depths" and "bits" based on the statistics 41 of the "input" string and stores it into the bit stream. 42 Note that the prefix code here is built from the pre-LZ77 input, therefore 43 we can only approximate the statistics of the actual literal stream. 44 Moreover, for long inputs we build a histogram from a sample of the input 45 and thus have to assign a non-zero depth for each literal. 46 Returns estimated compression ratio millibytes/char for encoding given input 47 with generated code. */ 48 func buildAndStoreLiteralPrefixCode(input []byte, input_size uint, depths []byte, bits []uint16, storage_ix *uint, storage []byte) uint { 49 var histogram = [256]uint32{0} 50 var histogram_total uint 51 var i uint 52 if input_size < 1<<15 { 53 for i = 0; i < input_size; i++ { 54 histogram[input[i]]++ 55 } 56 57 histogram_total = input_size 58 for i = 0; i < 256; i++ { 59 /* We weigh the first 11 samples with weight 3 to account for the 60 balancing effect of the LZ77 phase on the histogram. */ 61 var adjust uint32 = 2 * brotli_min_uint32_t(histogram[i], 11) 62 histogram[i] += adjust 63 histogram_total += uint(adjust) 64 } 65 } else { 66 const kSampleRate uint = 29 67 for i = 0; i < input_size; i += kSampleRate { 68 histogram[input[i]]++ 69 } 70 71 histogram_total = (input_size + kSampleRate - 1) / kSampleRate 72 for i = 0; i < 256; i++ { 73 /* We add 1 to each population count to avoid 0 bit depths (since this is 74 only a sample and we don't know if the symbol appears or not), and we 75 weigh the first 11 samples with weight 3 to account for the balancing 76 effect of the LZ77 phase on the histogram (more frequent symbols are 77 more likely to be in backward references instead as literals). */ 78 var adjust uint32 = 1 + 2*brotli_min_uint32_t(histogram[i], 11) 79 histogram[i] += adjust 80 histogram_total += uint(adjust) 81 } 82 } 83 84 buildAndStoreHuffmanTreeFast(histogram[:], histogram_total, /* max_bits = */ 85 8, depths, bits, storage_ix, storage) 86 { 87 var literal_ratio uint = 0 88 for i = 0; i < 256; i++ { 89 if histogram[i] != 0 { 90 literal_ratio += uint(histogram[i] * uint32(depths[i])) 91 } 92 } 93 94 /* Estimated encoding ratio, millibytes per symbol. */ 95 return (literal_ratio * 125) / histogram_total 96 } 97 } 98 99 /* Builds a command and distance prefix code (each 64 symbols) into "depth" and 100 "bits" based on "histogram" and stores it into the bit stream. */ 101 func buildAndStoreCommandPrefixCode1(histogram []uint32, depth []byte, bits []uint16, storage_ix *uint, storage []byte) { 102 var tree [129]huffmanTree 103 var cmd_depth = [numCommandSymbols]byte{0} 104 /* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */ 105 106 var cmd_bits [64]uint16 107 108 createHuffmanTree(histogram, 64, 15, tree[:], depth) 109 createHuffmanTree(histogram[64:], 64, 14, tree[:], depth[64:]) 110 111 /* We have to jump through a few hoops here in order to compute 112 the command bits because the symbols are in a different order than in 113 the full alphabet. This looks complicated, but having the symbols 114 in this order in the command bits saves a few branches in the Emit* 115 functions. */ 116 copy(cmd_depth[:], depth[:24]) 117 118 copy(cmd_depth[24:][:], depth[40:][:8]) 119 copy(cmd_depth[32:][:], depth[24:][:8]) 120 copy(cmd_depth[40:][:], depth[48:][:8]) 121 copy(cmd_depth[48:][:], depth[32:][:8]) 122 copy(cmd_depth[56:][:], depth[56:][:8]) 123 convertBitDepthsToSymbols(cmd_depth[:], 64, cmd_bits[:]) 124 copy(bits, cmd_bits[:24]) 125 copy(bits[24:], cmd_bits[32:][:8]) 126 copy(bits[32:], cmd_bits[48:][:8]) 127 copy(bits[40:], cmd_bits[24:][:8]) 128 copy(bits[48:], cmd_bits[40:][:8]) 129 copy(bits[56:], cmd_bits[56:][:8]) 130 convertBitDepthsToSymbols(depth[64:], 64, bits[64:]) 131 { 132 /* Create the bit length array for the full command alphabet. */ 133 var i uint 134 for i := 0; i < int(64); i++ { 135 cmd_depth[i] = 0 136 } /* only 64 first values were used */ 137 copy(cmd_depth[:], depth[:8]) 138 copy(cmd_depth[64:][:], depth[8:][:8]) 139 copy(cmd_depth[128:][:], depth[16:][:8]) 140 copy(cmd_depth[192:][:], depth[24:][:8]) 141 copy(cmd_depth[384:][:], depth[32:][:8]) 142 for i = 0; i < 8; i++ { 143 cmd_depth[128+8*i] = depth[40+i] 144 cmd_depth[256+8*i] = depth[48+i] 145 cmd_depth[448+8*i] = depth[56+i] 146 } 147 148 storeHuffmanTree(cmd_depth[:], numCommandSymbols, tree[:], storage_ix, storage) 149 } 150 151 storeHuffmanTree(depth[64:], 64, tree[:], storage_ix, storage) 152 } 153 154 /* REQUIRES: insertlen < 6210 */ 155 func emitInsertLen1(insertlen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) { 156 if insertlen < 6 { 157 var code uint = insertlen + 40 158 writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage) 159 histo[code]++ 160 } else if insertlen < 130 { 161 var tail uint = insertlen - 2 162 var nbits uint32 = log2FloorNonZero(tail) - 1 163 var prefix uint = tail >> nbits 164 var inscode uint = uint((nbits << 1) + uint32(prefix) + 42) 165 writeBits(uint(depth[inscode]), uint64(bits[inscode]), storage_ix, storage) 166 writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<<nbits), storage_ix, storage) 167 histo[inscode]++ 168 } else if insertlen < 2114 { 169 var tail uint = insertlen - 66 170 var nbits uint32 = log2FloorNonZero(tail) 171 var code uint = uint(nbits + 50) 172 writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage) 173 writeBits(uint(nbits), uint64(tail)-(uint64(uint(1))<<nbits), storage_ix, storage) 174 histo[code]++ 175 } else { 176 writeBits(uint(depth[61]), uint64(bits[61]), storage_ix, storage) 177 writeBits(12, uint64(insertlen)-2114, storage_ix, storage) 178 histo[61]++ 179 } 180 } 181 182 func emitLongInsertLen(insertlen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) { 183 if insertlen < 22594 { 184 writeBits(uint(depth[62]), uint64(bits[62]), storage_ix, storage) 185 writeBits(14, uint64(insertlen)-6210, storage_ix, storage) 186 histo[62]++ 187 } else { 188 writeBits(uint(depth[63]), uint64(bits[63]), storage_ix, storage) 189 writeBits(24, uint64(insertlen)-22594, storage_ix, storage) 190 histo[63]++ 191 } 192 } 193 194 func emitCopyLen1(copylen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) { 195 if copylen < 10 { 196 writeBits(uint(depth[copylen+14]), uint64(bits[copylen+14]), storage_ix, storage) 197 histo[copylen+14]++ 198 } else if copylen < 134 { 199 var tail uint = copylen - 6 200 var nbits uint32 = log2FloorNonZero(tail) - 1 201 var prefix uint = tail >> nbits 202 var code uint = uint((nbits << 1) + uint32(prefix) + 20) 203 writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage) 204 writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<<nbits), storage_ix, storage) 205 histo[code]++ 206 } else if copylen < 2118 { 207 var tail uint = copylen - 70 208 var nbits uint32 = log2FloorNonZero(tail) 209 var code uint = uint(nbits + 28) 210 writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage) 211 writeBits(uint(nbits), uint64(tail)-(uint64(uint(1))<<nbits), storage_ix, storage) 212 histo[code]++ 213 } else { 214 writeBits(uint(depth[39]), uint64(bits[39]), storage_ix, storage) 215 writeBits(24, uint64(copylen)-2118, storage_ix, storage) 216 histo[39]++ 217 } 218 } 219 220 func emitCopyLenLastDistance1(copylen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) { 221 if copylen < 12 { 222 writeBits(uint(depth[copylen-4]), uint64(bits[copylen-4]), storage_ix, storage) 223 histo[copylen-4]++ 224 } else if copylen < 72 { 225 var tail uint = copylen - 8 226 var nbits uint32 = log2FloorNonZero(tail) - 1 227 var prefix uint = tail >> nbits 228 var code uint = uint((nbits << 1) + uint32(prefix) + 4) 229 writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage) 230 writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<<nbits), storage_ix, storage) 231 histo[code]++ 232 } else if copylen < 136 { 233 var tail uint = copylen - 8 234 var code uint = (tail >> 5) + 30 235 writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage) 236 writeBits(5, uint64(tail)&31, storage_ix, storage) 237 writeBits(uint(depth[64]), uint64(bits[64]), storage_ix, storage) 238 histo[code]++ 239 histo[64]++ 240 } else if copylen < 2120 { 241 var tail uint = copylen - 72 242 var nbits uint32 = log2FloorNonZero(tail) 243 var code uint = uint(nbits + 28) 244 writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage) 245 writeBits(uint(nbits), uint64(tail)-(uint64(uint(1))<<nbits), storage_ix, storage) 246 writeBits(uint(depth[64]), uint64(bits[64]), storage_ix, storage) 247 histo[code]++ 248 histo[64]++ 249 } else { 250 writeBits(uint(depth[39]), uint64(bits[39]), storage_ix, storage) 251 writeBits(24, uint64(copylen)-2120, storage_ix, storage) 252 writeBits(uint(depth[64]), uint64(bits[64]), storage_ix, storage) 253 histo[39]++ 254 histo[64]++ 255 } 256 } 257 258 func emitDistance1(distance uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) { 259 var d uint = distance + 3 260 var nbits uint32 = log2FloorNonZero(d) - 1 261 var prefix uint = (d >> nbits) & 1 262 var offset uint = (2 + prefix) << nbits 263 var distcode uint = uint(2*(nbits-1) + uint32(prefix) + 80) 264 writeBits(uint(depth[distcode]), uint64(bits[distcode]), storage_ix, storage) 265 writeBits(uint(nbits), uint64(d)-uint64(offset), storage_ix, storage) 266 histo[distcode]++ 267 } 268 269 func emitLiterals(input []byte, len uint, depth []byte, bits []uint16, storage_ix *uint, storage []byte) { 270 var j uint 271 for j = 0; j < len; j++ { 272 var lit byte = input[j] 273 writeBits(uint(depth[lit]), uint64(bits[lit]), storage_ix, storage) 274 } 275 } 276 277 /* REQUIRES: len <= 1 << 24. */ 278 func storeMetaBlockHeader1(len uint, is_uncompressed bool, storage_ix *uint, storage []byte) { 279 var nibbles uint = 6 280 281 /* ISLAST */ 282 writeBits(1, 0, storage_ix, storage) 283 284 if len <= 1<<16 { 285 nibbles = 4 286 } else if len <= 1<<20 { 287 nibbles = 5 288 } 289 290 writeBits(2, uint64(nibbles)-4, storage_ix, storage) 291 writeBits(nibbles*4, uint64(len)-1, storage_ix, storage) 292 293 /* ISUNCOMPRESSED */ 294 writeSingleBit(is_uncompressed, storage_ix, storage) 295 } 296 297 func updateBits(n_bits uint, bits uint32, pos uint, array []byte) { 298 for n_bits > 0 { 299 var byte_pos uint = pos >> 3 300 var n_unchanged_bits uint = pos & 7 301 var n_changed_bits uint = brotli_min_size_t(n_bits, 8-n_unchanged_bits) 302 var total_bits uint = n_unchanged_bits + n_changed_bits 303 var mask uint32 = (^((1 << total_bits) - 1)) | ((1 << n_unchanged_bits) - 1) 304 var unchanged_bits uint32 = uint32(array[byte_pos]) & mask 305 var changed_bits uint32 = bits & ((1 << n_changed_bits) - 1) 306 array[byte_pos] = byte(changed_bits<<n_unchanged_bits | unchanged_bits) 307 n_bits -= n_changed_bits 308 bits >>= n_changed_bits 309 pos += n_changed_bits 310 } 311 } 312 313 func rewindBitPosition1(new_storage_ix uint, storage_ix *uint, storage []byte) { 314 var bitpos uint = new_storage_ix & 7 315 var mask uint = (1 << bitpos) - 1 316 storage[new_storage_ix>>3] &= byte(mask) 317 *storage_ix = new_storage_ix 318 } 319 320 var shouldMergeBlock_kSampleRate uint = 43 321 322 func shouldMergeBlock(data []byte, len uint, depths []byte) bool { 323 var histo = [256]uint{0} 324 var i uint 325 for i = 0; i < len; i += shouldMergeBlock_kSampleRate { 326 histo[data[i]]++ 327 } 328 { 329 var total uint = (len + shouldMergeBlock_kSampleRate - 1) / shouldMergeBlock_kSampleRate 330 var r float64 = (fastLog2(total)+0.5)*float64(total) + 200 331 for i = 0; i < 256; i++ { 332 r -= float64(histo[i]) * (float64(depths[i]) + fastLog2(histo[i])) 333 } 334 335 return r >= 0.0 336 } 337 } 338 339 func shouldUseUncompressedMode(metablock_start []byte, next_emit []byte, insertlen uint, literal_ratio uint) bool { 340 var compressed uint = uint(-cap(next_emit) + cap(metablock_start)) 341 if compressed*50 > insertlen { 342 return false 343 } else { 344 return literal_ratio > 980 345 } 346 } 347 348 func emitUncompressedMetaBlock1(begin []byte, end []byte, storage_ix_start uint, storage_ix *uint, storage []byte) { 349 var len uint = uint(-cap(end) + cap(begin)) 350 rewindBitPosition1(storage_ix_start, storage_ix, storage) 351 storeMetaBlockHeader1(uint(len), true, storage_ix, storage) 352 *storage_ix = (*storage_ix + 7) &^ 7 353 copy(storage[*storage_ix>>3:], begin[:len]) 354 *storage_ix += uint(len << 3) 355 storage[*storage_ix>>3] = 0 356 } 357 358 var kCmdHistoSeed = [128]uint32{ 359 0, 360 1, 361 1, 362 1, 363 1, 364 1, 365 1, 366 1, 367 1, 368 1, 369 1, 370 1, 371 1, 372 1, 373 1, 374 1, 375 0, 376 0, 377 0, 378 1, 379 1, 380 1, 381 1, 382 1, 383 1, 384 1, 385 1, 386 1, 387 1, 388 1, 389 1, 390 1, 391 1, 392 1, 393 1, 394 1, 395 1, 396 1, 397 1, 398 1, 399 0, 400 1, 401 1, 402 1, 403 1, 404 1, 405 1, 406 1, 407 1, 408 1, 409 1, 410 1, 411 1, 412 1, 413 1, 414 1, 415 1, 416 1, 417 1, 418 1, 419 1, 420 1, 421 1, 422 1, 423 1, 424 0, 425 0, 426 0, 427 0, 428 0, 429 0, 430 0, 431 0, 432 0, 433 0, 434 0, 435 0, 436 0, 437 0, 438 0, 439 1, 440 1, 441 1, 442 1, 443 1, 444 1, 445 1, 446 1, 447 1, 448 1, 449 1, 450 1, 451 1, 452 1, 453 1, 454 1, 455 1, 456 1, 457 1, 458 1, 459 1, 460 1, 461 1, 462 1, 463 1, 464 1, 465 1, 466 1, 467 1, 468 1, 469 1, 470 1, 471 1, 472 1, 473 1, 474 1, 475 1, 476 1, 477 1, 478 1, 479 1, 480 1, 481 1, 482 1, 483 0, 484 0, 485 0, 486 0, 487 } 488 489 var compressFragmentFastImpl_kFirstBlockSize uint = 3 << 15 490 var compressFragmentFastImpl_kMergeBlockSize uint = 1 << 16 491 492 func compressFragmentFastImpl(in []byte, input_size uint, is_last bool, table []int, table_bits uint, cmd_depth []byte, cmd_bits []uint16, cmd_code_numbits *uint, cmd_code []byte, storage_ix *uint, storage []byte) { 493 var cmd_histo [128]uint32 494 var ip_end int 495 var next_emit int = 0 496 var base_ip int = 0 497 var input int = 0 498 const kInputMarginBytes uint = windowGap 499 const kMinMatchLen uint = 5 500 var metablock_start int = input 501 var block_size uint = brotli_min_size_t(input_size, compressFragmentFastImpl_kFirstBlockSize) 502 var total_block_size uint = block_size 503 var mlen_storage_ix uint = *storage_ix + 3 504 var lit_depth [256]byte 505 var lit_bits [256]uint16 506 var literal_ratio uint 507 var ip int 508 var last_distance int 509 var shift uint = 64 - table_bits 510 511 /* "next_emit" is a pointer to the first byte that is not covered by a 512 previous copy. Bytes between "next_emit" and the start of the next copy or 513 the end of the input will be emitted as literal bytes. */ 514 515 /* Save the start of the first block for position and distance computations. 516 */ 517 518 /* Save the bit position of the MLEN field of the meta-block header, so that 519 we can update it later if we decide to extend this meta-block. */ 520 storeMetaBlockHeader1(block_size, false, storage_ix, storage) 521 522 /* No block splits, no contexts. */ 523 writeBits(13, 0, storage_ix, storage) 524 525 literal_ratio = buildAndStoreLiteralPrefixCode(in[input:], block_size, lit_depth[:], lit_bits[:], storage_ix, storage) 526 { 527 /* Store the pre-compressed command and distance prefix codes. */ 528 var i uint 529 for i = 0; i+7 < *cmd_code_numbits; i += 8 { 530 writeBits(8, uint64(cmd_code[i>>3]), storage_ix, storage) 531 } 532 } 533 534 writeBits(*cmd_code_numbits&7, uint64(cmd_code[*cmd_code_numbits>>3]), storage_ix, storage) 535 536 /* Initialize the command and distance histograms. We will gather 537 statistics of command and distance codes during the processing 538 of this block and use it to update the command and distance 539 prefix codes for the next block. */ 540 emit_commands: 541 copy(cmd_histo[:], kCmdHistoSeed[:]) 542 543 /* "ip" is the input pointer. */ 544 ip = input 545 546 last_distance = -1 547 ip_end = int(uint(input) + block_size) 548 549 if block_size >= kInputMarginBytes { 550 var len_limit uint = brotli_min_size_t(block_size-kMinMatchLen, input_size-kInputMarginBytes) 551 var ip_limit int = int(uint(input) + len_limit) 552 /* For the last block, we need to keep a 16 bytes margin so that we can be 553 sure that all distances are at most window size - 16. 554 For all other blocks, we only need to keep a margin of 5 bytes so that 555 we don't go over the block size with a copy. */ 556 557 var next_hash uint32 558 ip++ 559 for next_hash = hash5(in[ip:], shift); ; { 560 var skip uint32 = 32 561 var next_ip int = ip 562 /* Step 1: Scan forward in the input looking for a 5-byte-long match. 563 If we get close to exhausting the input then goto emit_remainder. 564 565 Heuristic match skipping: If 32 bytes are scanned with no matches 566 found, start looking only at every other byte. If 32 more bytes are 567 scanned, look at every third byte, etc.. When a match is found, 568 immediately go back to looking at every byte. This is a small loss 569 (~5% performance, ~0.1% density) for compressible data due to more 570 bookkeeping, but for non-compressible data (such as JPEG) it's a huge 571 win since the compressor quickly "realizes" the data is incompressible 572 and doesn't bother looking for matches everywhere. 573 574 The "skip" variable keeps track of how many bytes there are since the 575 last match; dividing it by 32 (i.e. right-shifting by five) gives the 576 number of bytes to move ahead for each iteration. */ 577 578 var candidate int 579 assert(next_emit < ip) 580 581 trawl: 582 for { 583 var hash uint32 = next_hash 584 var bytes_between_hash_lookups uint32 = skip >> 5 585 skip++ 586 assert(hash == hash5(in[next_ip:], shift)) 587 ip = next_ip 588 next_ip = int(uint32(ip) + bytes_between_hash_lookups) 589 if next_ip > ip_limit { 590 goto emit_remainder 591 } 592 593 next_hash = hash5(in[next_ip:], shift) 594 candidate = ip - last_distance 595 if isMatch5(in[ip:], in[candidate:]) { 596 if candidate < ip { 597 table[hash] = int(ip - base_ip) 598 break 599 } 600 } 601 602 candidate = base_ip + table[hash] 603 assert(candidate >= base_ip) 604 assert(candidate < ip) 605 606 table[hash] = int(ip - base_ip) 607 if isMatch5(in[ip:], in[candidate:]) { 608 break 609 } 610 } 611 612 /* Check copy distance. If candidate is not feasible, continue search. 613 Checking is done outside of hot loop to reduce overhead. */ 614 if ip-candidate > maxDistance_compress_fragment { 615 goto trawl 616 } 617 618 /* Step 2: Emit the found match together with the literal bytes from 619 "next_emit" to the bit stream, and then see if we can find a next match 620 immediately afterwards. Repeat until we find no match for the input 621 without emitting some literal bytes. */ 622 { 623 var base int = ip 624 /* > 0 */ 625 var matched uint = 5 + findMatchLengthWithLimit(in[candidate+5:], in[ip+5:], uint(ip_end-ip)-5) 626 var distance int = int(base - candidate) 627 /* We have a 5-byte match at ip, and we need to emit bytes in 628 [next_emit, ip). */ 629 630 var insert uint = uint(base - next_emit) 631 ip += int(matched) 632 if insert < 6210 { 633 emitInsertLen1(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage) 634 } else if shouldUseUncompressedMode(in[metablock_start:], in[next_emit:], insert, literal_ratio) { 635 emitUncompressedMetaBlock1(in[metablock_start:], in[base:], mlen_storage_ix-3, storage_ix, storage) 636 input_size -= uint(base - input) 637 input = base 638 next_emit = input 639 goto next_block 640 } else { 641 emitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage) 642 } 643 644 emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage) 645 if distance == last_distance { 646 writeBits(uint(cmd_depth[64]), uint64(cmd_bits[64]), storage_ix, storage) 647 cmd_histo[64]++ 648 } else { 649 emitDistance1(uint(distance), cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage) 650 last_distance = distance 651 } 652 653 emitCopyLenLastDistance1(matched, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage) 654 655 next_emit = ip 656 if ip >= ip_limit { 657 goto emit_remainder 658 } 659 660 /* We could immediately start working at ip now, but to improve 661 compression we first update "table" with the hashes of some positions 662 within the last copy. */ 663 { 664 var input_bytes uint64 = binary.LittleEndian.Uint64(in[ip-3:]) 665 var prev_hash uint32 = hashBytesAtOffset5(input_bytes, 0, shift) 666 var cur_hash uint32 = hashBytesAtOffset5(input_bytes, 3, shift) 667 table[prev_hash] = int(ip - base_ip - 3) 668 prev_hash = hashBytesAtOffset5(input_bytes, 1, shift) 669 table[prev_hash] = int(ip - base_ip - 2) 670 prev_hash = hashBytesAtOffset5(input_bytes, 2, shift) 671 table[prev_hash] = int(ip - base_ip - 1) 672 673 candidate = base_ip + table[cur_hash] 674 table[cur_hash] = int(ip - base_ip) 675 } 676 } 677 678 for isMatch5(in[ip:], in[candidate:]) { 679 var base int = ip 680 /* We have a 5-byte match at ip, and no need to emit any literal bytes 681 prior to ip. */ 682 683 var matched uint = 5 + findMatchLengthWithLimit(in[candidate+5:], in[ip+5:], uint(ip_end-ip)-5) 684 if ip-candidate > maxDistance_compress_fragment { 685 break 686 } 687 ip += int(matched) 688 last_distance = int(base - candidate) /* > 0 */ 689 emitCopyLen1(matched, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage) 690 emitDistance1(uint(last_distance), cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage) 691 692 next_emit = ip 693 if ip >= ip_limit { 694 goto emit_remainder 695 } 696 697 /* We could immediately start working at ip now, but to improve 698 compression we first update "table" with the hashes of some positions 699 within the last copy. */ 700 { 701 var input_bytes uint64 = binary.LittleEndian.Uint64(in[ip-3:]) 702 var prev_hash uint32 = hashBytesAtOffset5(input_bytes, 0, shift) 703 var cur_hash uint32 = hashBytesAtOffset5(input_bytes, 3, shift) 704 table[prev_hash] = int(ip - base_ip - 3) 705 prev_hash = hashBytesAtOffset5(input_bytes, 1, shift) 706 table[prev_hash] = int(ip - base_ip - 2) 707 prev_hash = hashBytesAtOffset5(input_bytes, 2, shift) 708 table[prev_hash] = int(ip - base_ip - 1) 709 710 candidate = base_ip + table[cur_hash] 711 table[cur_hash] = int(ip - base_ip) 712 } 713 } 714 715 ip++ 716 next_hash = hash5(in[ip:], shift) 717 } 718 } 719 720 emit_remainder: 721 assert(next_emit <= ip_end) 722 input += int(block_size) 723 input_size -= block_size 724 block_size = brotli_min_size_t(input_size, compressFragmentFastImpl_kMergeBlockSize) 725 726 /* Decide if we want to continue this meta-block instead of emitting the 727 last insert-only command. */ 728 if input_size > 0 && total_block_size+block_size <= 1<<20 && shouldMergeBlock(in[input:], block_size, lit_depth[:]) { 729 assert(total_block_size > 1<<16) 730 731 /* Update the size of the current meta-block and continue emitting commands. 732 We can do this because the current size and the new size both have 5 733 nibbles. */ 734 total_block_size += block_size 735 736 updateBits(20, uint32(total_block_size-1), mlen_storage_ix, storage) 737 goto emit_commands 738 } 739 740 /* Emit the remaining bytes as literals. */ 741 if next_emit < ip_end { 742 var insert uint = uint(ip_end - next_emit) 743 if insert < 6210 { 744 emitInsertLen1(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage) 745 emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage) 746 } else if shouldUseUncompressedMode(in[metablock_start:], in[next_emit:], insert, literal_ratio) { 747 emitUncompressedMetaBlock1(in[metablock_start:], in[ip_end:], mlen_storage_ix-3, storage_ix, storage) 748 } else { 749 emitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage) 750 emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage) 751 } 752 } 753 754 next_emit = ip_end 755 756 /* If we have more data, write a new meta-block header and prefix codes and 757 then continue emitting commands. */ 758 next_block: 759 if input_size > 0 { 760 metablock_start = input 761 block_size = brotli_min_size_t(input_size, compressFragmentFastImpl_kFirstBlockSize) 762 total_block_size = block_size 763 764 /* Save the bit position of the MLEN field of the meta-block header, so that 765 we can update it later if we decide to extend this meta-block. */ 766 mlen_storage_ix = *storage_ix + 3 767 768 storeMetaBlockHeader1(block_size, false, storage_ix, storage) 769 770 /* No block splits, no contexts. */ 771 writeBits(13, 0, storage_ix, storage) 772 773 literal_ratio = buildAndStoreLiteralPrefixCode(in[input:], block_size, lit_depth[:], lit_bits[:], storage_ix, storage) 774 buildAndStoreCommandPrefixCode1(cmd_histo[:], cmd_depth, cmd_bits, storage_ix, storage) 775 goto emit_commands 776 } 777 778 if !is_last { 779 /* If this is not the last block, update the command and distance prefix 780 codes for the next block and store the compressed forms. */ 781 cmd_code[0] = 0 782 783 *cmd_code_numbits = 0 784 buildAndStoreCommandPrefixCode1(cmd_histo[:], cmd_depth, cmd_bits, cmd_code_numbits, cmd_code) 785 } 786 } 787 788 /* Compresses "input" string to the "*storage" buffer as one or more complete 789 meta-blocks, and updates the "*storage_ix" bit position. 790 791 If "is_last" is 1, emits an additional empty last meta-block. 792 793 "cmd_depth" and "cmd_bits" contain the command and distance prefix codes 794 (see comment in encode.h) used for the encoding of this input fragment. 795 If "is_last" is 0, they are updated to reflect the statistics 796 of this input fragment, to be used for the encoding of the next fragment. 797 798 "*cmd_code_numbits" is the number of bits of the compressed representation 799 of the command and distance prefix codes, and "cmd_code" is an array of 800 at least "(*cmd_code_numbits + 7) >> 3" size that contains the compressed 801 command and distance prefix codes. If "is_last" is 0, these are also 802 updated to represent the updated "cmd_depth" and "cmd_bits". 803 804 REQUIRES: "input_size" is greater than zero, or "is_last" is 1. 805 REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24). 806 REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero. 807 REQUIRES: "table_size" is an odd (9, 11, 13, 15) power of two 808 OUTPUT: maximal copy distance <= |input_size| 809 OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */ 810 func compressFragmentFast(input []byte, input_size uint, is_last bool, table []int, table_size uint, cmd_depth []byte, cmd_bits []uint16, cmd_code_numbits *uint, cmd_code []byte, storage_ix *uint, storage []byte) { 811 var initial_storage_ix uint = *storage_ix 812 var table_bits uint = uint(log2FloorNonZero(table_size)) 813 814 if input_size == 0 { 815 assert(is_last) 816 writeBits(1, 1, storage_ix, storage) /* islast */ 817 writeBits(1, 1, storage_ix, storage) /* isempty */ 818 *storage_ix = (*storage_ix + 7) &^ 7 819 return 820 } 821 822 compressFragmentFastImpl(input, input_size, is_last, table, table_bits, cmd_depth, cmd_bits, cmd_code_numbits, cmd_code, storage_ix, storage) 823 824 /* If output is larger than single uncompressed block, rewrite it. */ 825 if *storage_ix-initial_storage_ix > 31+(input_size<<3) { 826 emitUncompressedMetaBlock1(input, input[input_size:], initial_storage_ix, storage_ix, storage) 827 } 828 829 if is_last { 830 writeBits(1, 1, storage_ix, storage) /* islast */ 831 writeBits(1, 1, storage_ix, storage) /* isempty */ 832 *storage_ix = (*storage_ix + 7) &^ 7 833 } 834 }