github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/github.com/klauspost/compress/zstd/blockenc.go (about) 1 // Copyright 2019+ Klaus Post. All rights reserved. 2 // License information can be found in the LICENSE file. 3 // Based on work by Yann Collet, released under BSD License. 4 5 package zstd 6 7 import ( 8 "errors" 9 "fmt" 10 "math" 11 "math/bits" 12 13 "github.com/klauspost/compress/huff0" 14 ) 15 16 type blockEnc struct { 17 size int 18 literals []byte 19 sequences []seq 20 coders seqCoders 21 litEnc *huff0.Scratch 22 dictLitEnc *huff0.Scratch 23 wr bitWriter 24 25 extraLits int 26 output []byte 27 recentOffsets [3]uint32 28 prevRecentOffsets [3]uint32 29 30 last bool 31 lowMem bool 32 } 33 34 // init should be used once the block has been created. 35 // If called more than once, the effect is the same as calling reset. 36 func (b *blockEnc) init() { 37 if b.lowMem { 38 // 1K literals 39 if cap(b.literals) < 1<<10 { 40 b.literals = make([]byte, 0, 1<<10) 41 } 42 const defSeqs = 20 43 if cap(b.sequences) < defSeqs { 44 b.sequences = make([]seq, 0, defSeqs) 45 } 46 // 1K 47 if cap(b.output) < 1<<10 { 48 b.output = make([]byte, 0, 1<<10) 49 } 50 } else { 51 if cap(b.literals) < maxCompressedBlockSize { 52 b.literals = make([]byte, 0, maxCompressedBlockSize) 53 } 54 const defSeqs = 2000 55 if cap(b.sequences) < defSeqs { 56 b.sequences = make([]seq, 0, defSeqs) 57 } 58 if cap(b.output) < maxCompressedBlockSize { 59 b.output = make([]byte, 0, maxCompressedBlockSize) 60 } 61 } 62 63 if b.coders.mlEnc == nil { 64 b.coders.mlEnc = &fseEncoder{} 65 b.coders.mlPrev = &fseEncoder{} 66 b.coders.ofEnc = &fseEncoder{} 67 b.coders.ofPrev = &fseEncoder{} 68 b.coders.llEnc = &fseEncoder{} 69 b.coders.llPrev = &fseEncoder{} 70 } 71 b.litEnc = &huff0.Scratch{WantLogLess: 4} 72 b.reset(nil) 73 } 74 75 // initNewEncode can be used to reset offsets and encoders to the initial state. 76 func (b *blockEnc) initNewEncode() { 77 b.recentOffsets = [3]uint32{1, 4, 8} 78 b.litEnc.Reuse = huff0.ReusePolicyNone 79 b.coders.setPrev(nil, nil, nil) 80 } 81 82 // reset will reset the block for a new encode, but in the same stream, 83 // meaning that state will be carried over, but the block content is reset. 84 // If a previous block is provided, the recent offsets are carried over. 85 func (b *blockEnc) reset(prev *blockEnc) { 86 b.extraLits = 0 87 b.literals = b.literals[:0] 88 b.size = 0 89 b.sequences = b.sequences[:0] 90 b.output = b.output[:0] 91 b.last = false 92 if prev != nil { 93 b.recentOffsets = prev.prevRecentOffsets 94 } 95 b.dictLitEnc = nil 96 } 97 98 // reset will reset the block for a new encode, but in the same stream, 99 // meaning that state will be carried over, but the block content is reset. 100 // If a previous block is provided, the recent offsets are carried over. 101 func (b *blockEnc) swapEncoders(prev *blockEnc) { 102 b.coders.swap(&prev.coders) 103 b.litEnc, prev.litEnc = prev.litEnc, b.litEnc 104 } 105 106 // blockHeader contains the information for a block header. 107 type blockHeader uint32 108 109 // setLast sets the 'last' indicator on a block. 110 func (h *blockHeader) setLast(b bool) { 111 if b { 112 *h = *h | 1 113 } else { 114 const mask = (1 << 24) - 2 115 *h = *h & mask 116 } 117 } 118 119 // setSize will store the compressed size of a block. 120 func (h *blockHeader) setSize(v uint32) { 121 const mask = 7 122 *h = (*h)&mask | blockHeader(v<<3) 123 } 124 125 // setType sets the block type. 126 func (h *blockHeader) setType(t blockType) { 127 const mask = 1 | (((1 << 24) - 1) ^ 7) 128 *h = (*h & mask) | blockHeader(t<<1) 129 } 130 131 // appendTo will append the block header to a slice. 132 func (h blockHeader) appendTo(b []byte) []byte { 133 return append(b, uint8(h), uint8(h>>8), uint8(h>>16)) 134 } 135 136 // String returns a string representation of the block. 137 func (h blockHeader) String() string { 138 return fmt.Sprintf("Type: %d, Size: %d, Last:%t", (h>>1)&3, h>>3, h&1 == 1) 139 } 140 141 // literalsHeader contains literals header information. 142 type literalsHeader uint64 143 144 // setType can be used to set the type of literal block. 145 func (h *literalsHeader) setType(t literalsBlockType) { 146 const mask = math.MaxUint64 - 3 147 *h = (*h & mask) | literalsHeader(t) 148 } 149 150 // setSize can be used to set a single size, for uncompressed and RLE content. 151 func (h *literalsHeader) setSize(regenLen int) { 152 inBits := bits.Len32(uint32(regenLen)) 153 // Only retain 2 bits 154 const mask = 3 155 lh := uint64(*h & mask) 156 switch { 157 case inBits < 5: 158 lh |= (uint64(regenLen) << 3) | (1 << 60) 159 if debugEncoder { 160 got := int(lh>>3) & 0xff 161 if got != regenLen { 162 panic(fmt.Sprint("litRegenSize = ", regenLen, "(want) != ", got, "(got)")) 163 } 164 } 165 case inBits < 12: 166 lh |= (1 << 2) | (uint64(regenLen) << 4) | (2 << 60) 167 case inBits < 20: 168 lh |= (3 << 2) | (uint64(regenLen) << 4) | (3 << 60) 169 default: 170 panic(fmt.Errorf("internal error: block too big (%d)", regenLen)) 171 } 172 *h = literalsHeader(lh) 173 } 174 175 // setSizes will set the size of a compressed literals section and the input length. 176 func (h *literalsHeader) setSizes(compLen, inLen int, single bool) { 177 compBits, inBits := bits.Len32(uint32(compLen)), bits.Len32(uint32(inLen)) 178 // Only retain 2 bits 179 const mask = 3 180 lh := uint64(*h & mask) 181 switch { 182 case compBits <= 10 && inBits <= 10: 183 if !single { 184 lh |= 1 << 2 185 } 186 lh |= (uint64(inLen) << 4) | (uint64(compLen) << (10 + 4)) | (3 << 60) 187 if debugEncoder { 188 const mmask = (1 << 24) - 1 189 n := (lh >> 4) & mmask 190 if int(n&1023) != inLen { 191 panic(fmt.Sprint("regensize:", int(n&1023), "!=", inLen, inBits)) 192 } 193 if int(n>>10) != compLen { 194 panic(fmt.Sprint("compsize:", int(n>>10), "!=", compLen, compBits)) 195 } 196 } 197 case compBits <= 14 && inBits <= 14: 198 lh |= (2 << 2) | (uint64(inLen) << 4) | (uint64(compLen) << (14 + 4)) | (4 << 60) 199 if single { 200 panic("single stream used with more than 10 bits length.") 201 } 202 case compBits <= 18 && inBits <= 18: 203 lh |= (3 << 2) | (uint64(inLen) << 4) | (uint64(compLen) << (18 + 4)) | (5 << 60) 204 if single { 205 panic("single stream used with more than 10 bits length.") 206 } 207 default: 208 panic("internal error: block too big") 209 } 210 *h = literalsHeader(lh) 211 } 212 213 // appendTo will append the literals header to a byte slice. 214 func (h literalsHeader) appendTo(b []byte) []byte { 215 size := uint8(h >> 60) 216 switch size { 217 case 1: 218 b = append(b, uint8(h)) 219 case 2: 220 b = append(b, uint8(h), uint8(h>>8)) 221 case 3: 222 b = append(b, uint8(h), uint8(h>>8), uint8(h>>16)) 223 case 4: 224 b = append(b, uint8(h), uint8(h>>8), uint8(h>>16), uint8(h>>24)) 225 case 5: 226 b = append(b, uint8(h), uint8(h>>8), uint8(h>>16), uint8(h>>24), uint8(h>>32)) 227 default: 228 panic(fmt.Errorf("internal error: literalsHeader has invalid size (%d)", size)) 229 } 230 return b 231 } 232 233 // size returns the output size with currently set values. 234 func (h literalsHeader) size() int { 235 return int(h >> 60) 236 } 237 238 func (h literalsHeader) String() string { 239 return fmt.Sprintf("Type: %d, SizeFormat: %d, Size: 0x%d, Bytes:%d", literalsBlockType(h&3), (h>>2)&3, h&((1<<60)-1)>>4, h>>60) 240 } 241 242 // pushOffsets will push the recent offsets to the backup store. 243 func (b *blockEnc) pushOffsets() { 244 b.prevRecentOffsets = b.recentOffsets 245 } 246 247 // pushOffsets will push the recent offsets to the backup store. 248 func (b *blockEnc) popOffsets() { 249 b.recentOffsets = b.prevRecentOffsets 250 } 251 252 // matchOffset will adjust recent offsets and return the adjusted one, 253 // if it matches a previous offset. 254 func (b *blockEnc) matchOffset(offset, lits uint32) uint32 { 255 // Check if offset is one of the recent offsets. 256 // Adjusts the output offset accordingly. 257 // Gives a tiny bit of compression, typically around 1%. 258 if true { 259 if lits > 0 { 260 switch offset { 261 case b.recentOffsets[0]: 262 offset = 1 263 case b.recentOffsets[1]: 264 b.recentOffsets[1] = b.recentOffsets[0] 265 b.recentOffsets[0] = offset 266 offset = 2 267 case b.recentOffsets[2]: 268 b.recentOffsets[2] = b.recentOffsets[1] 269 b.recentOffsets[1] = b.recentOffsets[0] 270 b.recentOffsets[0] = offset 271 offset = 3 272 default: 273 b.recentOffsets[2] = b.recentOffsets[1] 274 b.recentOffsets[1] = b.recentOffsets[0] 275 b.recentOffsets[0] = offset 276 offset += 3 277 } 278 } else { 279 switch offset { 280 case b.recentOffsets[1]: 281 b.recentOffsets[1] = b.recentOffsets[0] 282 b.recentOffsets[0] = offset 283 offset = 1 284 case b.recentOffsets[2]: 285 b.recentOffsets[2] = b.recentOffsets[1] 286 b.recentOffsets[1] = b.recentOffsets[0] 287 b.recentOffsets[0] = offset 288 offset = 2 289 case b.recentOffsets[0] - 1: 290 b.recentOffsets[2] = b.recentOffsets[1] 291 b.recentOffsets[1] = b.recentOffsets[0] 292 b.recentOffsets[0] = offset 293 offset = 3 294 default: 295 b.recentOffsets[2] = b.recentOffsets[1] 296 b.recentOffsets[1] = b.recentOffsets[0] 297 b.recentOffsets[0] = offset 298 offset += 3 299 } 300 } 301 } else { 302 offset += 3 303 } 304 return offset 305 } 306 307 // encodeRaw can be used to set the output to a raw representation of supplied bytes. 308 func (b *blockEnc) encodeRaw(a []byte) { 309 var bh blockHeader 310 bh.setLast(b.last) 311 bh.setSize(uint32(len(a))) 312 bh.setType(blockTypeRaw) 313 b.output = bh.appendTo(b.output[:0]) 314 b.output = append(b.output, a...) 315 if debugEncoder { 316 println("Adding RAW block, length", len(a), "last:", b.last) 317 } 318 } 319 320 // encodeRaw can be used to set the output to a raw representation of supplied bytes. 321 func (b *blockEnc) encodeRawTo(dst, src []byte) []byte { 322 var bh blockHeader 323 bh.setLast(b.last) 324 bh.setSize(uint32(len(src))) 325 bh.setType(blockTypeRaw) 326 dst = bh.appendTo(dst) 327 dst = append(dst, src...) 328 if debugEncoder { 329 println("Adding RAW block, length", len(src), "last:", b.last) 330 } 331 return dst 332 } 333 334 // encodeLits can be used if the block is only litLen. 335 func (b *blockEnc) encodeLits(lits []byte, raw bool) error { 336 var bh blockHeader 337 bh.setLast(b.last) 338 bh.setSize(uint32(len(lits))) 339 340 // Don't compress extremely small blocks 341 if len(lits) < 8 || (len(lits) < 32 && b.dictLitEnc == nil) || raw { 342 if debugEncoder { 343 println("Adding RAW block, length", len(lits), "last:", b.last) 344 } 345 bh.setType(blockTypeRaw) 346 b.output = bh.appendTo(b.output) 347 b.output = append(b.output, lits...) 348 return nil 349 } 350 351 var ( 352 out []byte 353 reUsed, single bool 354 err error 355 ) 356 if b.dictLitEnc != nil { 357 b.litEnc.TransferCTable(b.dictLitEnc) 358 b.litEnc.Reuse = huff0.ReusePolicyAllow 359 b.dictLitEnc = nil 360 } 361 if len(lits) >= 1024 { 362 // Use 4 Streams. 363 out, reUsed, err = huff0.Compress4X(lits, b.litEnc) 364 } else if len(lits) > 16 { 365 // Use 1 stream 366 single = true 367 out, reUsed, err = huff0.Compress1X(lits, b.litEnc) 368 } else { 369 err = huff0.ErrIncompressible 370 } 371 if err == nil && len(out)+5 > len(lits) { 372 // If we are close, we may still be worse or equal to raw. 373 var lh literalsHeader 374 lh.setSizes(len(out), len(lits), single) 375 if len(out)+lh.size() >= len(lits) { 376 err = huff0.ErrIncompressible 377 } 378 } 379 switch err { 380 case huff0.ErrIncompressible: 381 if debugEncoder { 382 println("Adding RAW block, length", len(lits), "last:", b.last) 383 } 384 bh.setType(blockTypeRaw) 385 b.output = bh.appendTo(b.output) 386 b.output = append(b.output, lits...) 387 return nil 388 case huff0.ErrUseRLE: 389 if debugEncoder { 390 println("Adding RLE block, length", len(lits)) 391 } 392 bh.setType(blockTypeRLE) 393 b.output = bh.appendTo(b.output) 394 b.output = append(b.output, lits[0]) 395 return nil 396 case nil: 397 default: 398 return err 399 } 400 // Compressed... 401 // Now, allow reuse 402 b.litEnc.Reuse = huff0.ReusePolicyAllow 403 bh.setType(blockTypeCompressed) 404 var lh literalsHeader 405 if reUsed { 406 if debugEncoder { 407 println("Reused tree, compressed to", len(out)) 408 } 409 lh.setType(literalsBlockTreeless) 410 } else { 411 if debugEncoder { 412 println("New tree, compressed to", len(out), "tree size:", len(b.litEnc.OutTable)) 413 } 414 lh.setType(literalsBlockCompressed) 415 } 416 // Set sizes 417 lh.setSizes(len(out), len(lits), single) 418 bh.setSize(uint32(len(out) + lh.size() + 1)) 419 420 // Write block headers. 421 b.output = bh.appendTo(b.output) 422 b.output = lh.appendTo(b.output) 423 // Add compressed data. 424 b.output = append(b.output, out...) 425 // No sequences. 426 b.output = append(b.output, 0) 427 return nil 428 } 429 430 // fuzzFseEncoder can be used to fuzz the FSE encoder. 431 func fuzzFseEncoder(data []byte) int { 432 if len(data) > maxSequences || len(data) < 2 { 433 return 0 434 } 435 enc := fseEncoder{} 436 hist := enc.Histogram() 437 maxSym := uint8(0) 438 for i, v := range data { 439 v = v & 63 440 data[i] = v 441 hist[v]++ 442 if v > maxSym { 443 maxSym = v 444 } 445 } 446 if maxSym == 0 { 447 // All 0 448 return 0 449 } 450 maxCount := func(a []uint32) int { 451 var max uint32 452 for _, v := range a { 453 if v > max { 454 max = v 455 } 456 } 457 return int(max) 458 } 459 cnt := maxCount(hist[:maxSym]) 460 if cnt == len(data) { 461 // RLE 462 return 0 463 } 464 enc.HistogramFinished(maxSym, cnt) 465 err := enc.normalizeCount(len(data)) 466 if err != nil { 467 return 0 468 } 469 _, err = enc.writeCount(nil) 470 if err != nil { 471 panic(err) 472 } 473 return 1 474 } 475 476 // encode will encode the block and append the output in b.output. 477 // Previous offset codes must be pushed if more blocks are expected. 478 func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error { 479 if len(b.sequences) == 0 { 480 return b.encodeLits(b.literals, rawAllLits) 481 } 482 // We want some difference to at least account for the headers. 483 saved := b.size - len(b.literals) - (b.size >> 6) 484 if saved < 16 { 485 if org == nil { 486 return errIncompressible 487 } 488 b.popOffsets() 489 return b.encodeLits(org, rawAllLits) 490 } 491 492 var bh blockHeader 493 var lh literalsHeader 494 bh.setLast(b.last) 495 bh.setType(blockTypeCompressed) 496 // Store offset of the block header. Needed when we know the size. 497 bhOffset := len(b.output) 498 b.output = bh.appendTo(b.output) 499 500 var ( 501 out []byte 502 reUsed, single bool 503 err error 504 ) 505 if b.dictLitEnc != nil { 506 b.litEnc.TransferCTable(b.dictLitEnc) 507 b.litEnc.Reuse = huff0.ReusePolicyAllow 508 b.dictLitEnc = nil 509 } 510 if len(b.literals) >= 1024 && !raw { 511 // Use 4 Streams. 512 out, reUsed, err = huff0.Compress4X(b.literals, b.litEnc) 513 } else if len(b.literals) > 16 && !raw { 514 // Use 1 stream 515 single = true 516 out, reUsed, err = huff0.Compress1X(b.literals, b.litEnc) 517 } else { 518 err = huff0.ErrIncompressible 519 } 520 521 if err == nil && len(out)+5 > len(b.literals) { 522 // If we are close, we may still be worse or equal to raw. 523 var lh literalsHeader 524 lh.setSize(len(b.literals)) 525 szRaw := lh.size() 526 lh.setSizes(len(out), len(b.literals), single) 527 szComp := lh.size() 528 if len(out)+szComp >= len(b.literals)+szRaw { 529 err = huff0.ErrIncompressible 530 } 531 } 532 switch err { 533 case huff0.ErrIncompressible: 534 lh.setType(literalsBlockRaw) 535 lh.setSize(len(b.literals)) 536 b.output = lh.appendTo(b.output) 537 b.output = append(b.output, b.literals...) 538 if debugEncoder { 539 println("Adding literals RAW, length", len(b.literals)) 540 } 541 case huff0.ErrUseRLE: 542 lh.setType(literalsBlockRLE) 543 lh.setSize(len(b.literals)) 544 b.output = lh.appendTo(b.output) 545 b.output = append(b.output, b.literals[0]) 546 if debugEncoder { 547 println("Adding literals RLE") 548 } 549 case nil: 550 // Compressed litLen... 551 if reUsed { 552 if debugEncoder { 553 println("reused tree") 554 } 555 lh.setType(literalsBlockTreeless) 556 } else { 557 if debugEncoder { 558 println("new tree, size:", len(b.litEnc.OutTable)) 559 } 560 lh.setType(literalsBlockCompressed) 561 if debugEncoder { 562 _, _, err := huff0.ReadTable(out, nil) 563 if err != nil { 564 panic(err) 565 } 566 } 567 } 568 lh.setSizes(len(out), len(b.literals), single) 569 if debugEncoder { 570 printf("Compressed %d literals to %d bytes", len(b.literals), len(out)) 571 println("Adding literal header:", lh) 572 } 573 b.output = lh.appendTo(b.output) 574 b.output = append(b.output, out...) 575 b.litEnc.Reuse = huff0.ReusePolicyAllow 576 if debugEncoder { 577 println("Adding literals compressed") 578 } 579 default: 580 if debugEncoder { 581 println("Adding literals ERROR:", err) 582 } 583 return err 584 } 585 // Sequence compression 586 587 // Write the number of sequences 588 switch { 589 case len(b.sequences) < 128: 590 b.output = append(b.output, uint8(len(b.sequences))) 591 case len(b.sequences) < 0x7f00: // TODO: this could be wrong 592 n := len(b.sequences) 593 b.output = append(b.output, 128+uint8(n>>8), uint8(n)) 594 default: 595 n := len(b.sequences) - 0x7f00 596 b.output = append(b.output, 255, uint8(n), uint8(n>>8)) 597 } 598 if debugEncoder { 599 println("Encoding", len(b.sequences), "sequences") 600 } 601 b.genCodes() 602 llEnc := b.coders.llEnc 603 ofEnc := b.coders.ofEnc 604 mlEnc := b.coders.mlEnc 605 err = llEnc.normalizeCount(len(b.sequences)) 606 if err != nil { 607 return err 608 } 609 err = ofEnc.normalizeCount(len(b.sequences)) 610 if err != nil { 611 return err 612 } 613 err = mlEnc.normalizeCount(len(b.sequences)) 614 if err != nil { 615 return err 616 } 617 618 // Choose the best compression mode for each type. 619 // Will evaluate the new vs predefined and previous. 620 chooseComp := func(cur, prev, preDef *fseEncoder) (*fseEncoder, seqCompMode) { 621 // See if predefined/previous is better 622 hist := cur.count[:cur.symbolLen] 623 nSize := cur.approxSize(hist) + cur.maxHeaderSize() 624 predefSize := preDef.approxSize(hist) 625 prevSize := prev.approxSize(hist) 626 627 // Add a small penalty for new encoders. 628 // Don't bother with extremely small (<2 byte gains). 629 nSize = nSize + (nSize+2*8*16)>>4 630 switch { 631 case predefSize <= prevSize && predefSize <= nSize || forcePreDef: 632 if debugEncoder { 633 println("Using predefined", predefSize>>3, "<=", nSize>>3) 634 } 635 return preDef, compModePredefined 636 case prevSize <= nSize: 637 if debugEncoder { 638 println("Using previous", prevSize>>3, "<=", nSize>>3) 639 } 640 return prev, compModeRepeat 641 default: 642 if debugEncoder { 643 println("Using new, predef", predefSize>>3, ". previous:", prevSize>>3, ">", nSize>>3, "header max:", cur.maxHeaderSize()>>3, "bytes") 644 println("tl:", cur.actualTableLog, "symbolLen:", cur.symbolLen, "norm:", cur.norm[:cur.symbolLen], "hist", cur.count[:cur.symbolLen]) 645 } 646 return cur, compModeFSE 647 } 648 } 649 650 // Write compression mode 651 var mode uint8 652 if llEnc.useRLE { 653 mode |= uint8(compModeRLE) << 6 654 llEnc.setRLE(b.sequences[0].llCode) 655 if debugEncoder { 656 println("llEnc.useRLE") 657 } 658 } else { 659 var m seqCompMode 660 llEnc, m = chooseComp(llEnc, b.coders.llPrev, &fsePredefEnc[tableLiteralLengths]) 661 mode |= uint8(m) << 6 662 } 663 if ofEnc.useRLE { 664 mode |= uint8(compModeRLE) << 4 665 ofEnc.setRLE(b.sequences[0].ofCode) 666 if debugEncoder { 667 println("ofEnc.useRLE") 668 } 669 } else { 670 var m seqCompMode 671 ofEnc, m = chooseComp(ofEnc, b.coders.ofPrev, &fsePredefEnc[tableOffsets]) 672 mode |= uint8(m) << 4 673 } 674 675 if mlEnc.useRLE { 676 mode |= uint8(compModeRLE) << 2 677 mlEnc.setRLE(b.sequences[0].mlCode) 678 if debugEncoder { 679 println("mlEnc.useRLE, code: ", b.sequences[0].mlCode, "value", b.sequences[0].matchLen) 680 } 681 } else { 682 var m seqCompMode 683 mlEnc, m = chooseComp(mlEnc, b.coders.mlPrev, &fsePredefEnc[tableMatchLengths]) 684 mode |= uint8(m) << 2 685 } 686 b.output = append(b.output, mode) 687 if debugEncoder { 688 printf("Compression modes: 0b%b", mode) 689 } 690 b.output, err = llEnc.writeCount(b.output) 691 if err != nil { 692 return err 693 } 694 start := len(b.output) 695 b.output, err = ofEnc.writeCount(b.output) 696 if err != nil { 697 return err 698 } 699 if false { 700 println("block:", b.output[start:], "tablelog", ofEnc.actualTableLog, "maxcount:", ofEnc.maxCount) 701 fmt.Printf("selected TableLog: %d, Symbol length: %d\n", ofEnc.actualTableLog, ofEnc.symbolLen) 702 for i, v := range ofEnc.norm[:ofEnc.symbolLen] { 703 fmt.Printf("%3d: %5d -> %4d \n", i, ofEnc.count[i], v) 704 } 705 } 706 b.output, err = mlEnc.writeCount(b.output) 707 if err != nil { 708 return err 709 } 710 711 // Maybe in block? 712 wr := &b.wr 713 wr.reset(b.output) 714 715 var ll, of, ml cState 716 717 // Current sequence 718 seq := len(b.sequences) - 1 719 s := b.sequences[seq] 720 llEnc.setBits(llBitsTable[:]) 721 mlEnc.setBits(mlBitsTable[:]) 722 ofEnc.setBits(nil) 723 724 llTT, ofTT, mlTT := llEnc.ct.symbolTT[:256], ofEnc.ct.symbolTT[:256], mlEnc.ct.symbolTT[:256] 725 726 // We have 3 bounds checks here (and in the loop). 727 // Since we are iterating backwards it is kinda hard to avoid. 728 llB, ofB, mlB := llTT[s.llCode], ofTT[s.ofCode], mlTT[s.mlCode] 729 ll.init(wr, &llEnc.ct, llB) 730 of.init(wr, &ofEnc.ct, ofB) 731 wr.flush32() 732 ml.init(wr, &mlEnc.ct, mlB) 733 734 // Each of these lookups also generates a bounds check. 735 wr.addBits32NC(s.litLen, llB.outBits) 736 wr.addBits32NC(s.matchLen, mlB.outBits) 737 wr.flush32() 738 wr.addBits32NC(s.offset, ofB.outBits) 739 if debugSequences { 740 println("Encoded seq", seq, s, "codes:", s.llCode, s.mlCode, s.ofCode, "states:", ll.state, ml.state, of.state, "bits:", llB, mlB, ofB) 741 } 742 seq-- 743 // Store sequences in reverse... 744 for seq >= 0 { 745 s = b.sequences[seq] 746 747 ofB := ofTT[s.ofCode] 748 wr.flush32() // tablelog max is below 8 for each, so it will fill max 24 bits. 749 //of.encode(ofB) 750 nbBitsOut := (uint32(of.state) + ofB.deltaNbBits) >> 16 751 dstState := int32(of.state>>(nbBitsOut&15)) + int32(ofB.deltaFindState) 752 wr.addBits16NC(of.state, uint8(nbBitsOut)) 753 of.state = of.stateTable[dstState] 754 755 // Accumulate extra bits. 756 outBits := ofB.outBits & 31 757 extraBits := uint64(s.offset & bitMask32[outBits]) 758 extraBitsN := outBits 759 760 mlB := mlTT[s.mlCode] 761 //ml.encode(mlB) 762 nbBitsOut = (uint32(ml.state) + mlB.deltaNbBits) >> 16 763 dstState = int32(ml.state>>(nbBitsOut&15)) + int32(mlB.deltaFindState) 764 wr.addBits16NC(ml.state, uint8(nbBitsOut)) 765 ml.state = ml.stateTable[dstState] 766 767 outBits = mlB.outBits & 31 768 extraBits = extraBits<<outBits | uint64(s.matchLen&bitMask32[outBits]) 769 extraBitsN += outBits 770 771 llB := llTT[s.llCode] 772 //ll.encode(llB) 773 nbBitsOut = (uint32(ll.state) + llB.deltaNbBits) >> 16 774 dstState = int32(ll.state>>(nbBitsOut&15)) + int32(llB.deltaFindState) 775 wr.addBits16NC(ll.state, uint8(nbBitsOut)) 776 ll.state = ll.stateTable[dstState] 777 778 outBits = llB.outBits & 31 779 extraBits = extraBits<<outBits | uint64(s.litLen&bitMask32[outBits]) 780 extraBitsN += outBits 781 782 wr.flush32() 783 wr.addBits64NC(extraBits, extraBitsN) 784 785 if debugSequences { 786 println("Encoded seq", seq, s) 787 } 788 789 seq-- 790 } 791 ml.flush(mlEnc.actualTableLog) 792 of.flush(ofEnc.actualTableLog) 793 ll.flush(llEnc.actualTableLog) 794 wr.close() 795 b.output = wr.out 796 797 // Maybe even add a bigger margin. 798 if len(b.output)-3-bhOffset >= b.size { 799 // Discard and encode as raw block. 800 b.output = b.encodeRawTo(b.output[:bhOffset], org) 801 b.popOffsets() 802 b.litEnc.Reuse = huff0.ReusePolicyNone 803 return nil 804 } 805 806 // Size is output minus block header. 807 bh.setSize(uint32(len(b.output)-bhOffset) - 3) 808 if debugEncoder { 809 println("Rewriting block header", bh) 810 } 811 _ = bh.appendTo(b.output[bhOffset:bhOffset]) 812 b.coders.setPrev(llEnc, mlEnc, ofEnc) 813 return nil 814 } 815 816 var errIncompressible = errors.New("incompressible") 817 818 func (b *blockEnc) genCodes() { 819 if len(b.sequences) == 0 { 820 // nothing to do 821 return 822 } 823 if len(b.sequences) > math.MaxUint16 { 824 panic("can only encode up to 64K sequences") 825 } 826 // No bounds checks after here: 827 llH := b.coders.llEnc.Histogram() 828 ofH := b.coders.ofEnc.Histogram() 829 mlH := b.coders.mlEnc.Histogram() 830 for i := range llH { 831 llH[i] = 0 832 } 833 for i := range ofH { 834 ofH[i] = 0 835 } 836 for i := range mlH { 837 mlH[i] = 0 838 } 839 840 var llMax, ofMax, mlMax uint8 841 for i := range b.sequences { 842 seq := &b.sequences[i] 843 v := llCode(seq.litLen) 844 seq.llCode = v 845 llH[v]++ 846 if v > llMax { 847 llMax = v 848 } 849 850 v = ofCode(seq.offset) 851 seq.ofCode = v 852 ofH[v]++ 853 if v > ofMax { 854 ofMax = v 855 } 856 857 v = mlCode(seq.matchLen) 858 seq.mlCode = v 859 mlH[v]++ 860 if v > mlMax { 861 mlMax = v 862 if debugAsserts && mlMax > maxMatchLengthSymbol { 863 panic(fmt.Errorf("mlMax > maxMatchLengthSymbol (%d), matchlen: %d", mlMax, seq.matchLen)) 864 } 865 } 866 } 867 maxCount := func(a []uint32) int { 868 var max uint32 869 for _, v := range a { 870 if v > max { 871 max = v 872 } 873 } 874 return int(max) 875 } 876 if debugAsserts && mlMax > maxMatchLengthSymbol { 877 panic(fmt.Errorf("mlMax > maxMatchLengthSymbol (%d)", mlMax)) 878 } 879 if debugAsserts && ofMax > maxOffsetBits { 880 panic(fmt.Errorf("ofMax > maxOffsetBits (%d)", ofMax)) 881 } 882 if debugAsserts && llMax > maxLiteralLengthSymbol { 883 panic(fmt.Errorf("llMax > maxLiteralLengthSymbol (%d)", llMax)) 884 } 885 886 b.coders.mlEnc.HistogramFinished(mlMax, maxCount(mlH[:mlMax+1])) 887 b.coders.ofEnc.HistogramFinished(ofMax, maxCount(ofH[:ofMax+1])) 888 b.coders.llEnc.HistogramFinished(llMax, maxCount(llH[:llMax+1])) 889 }