package huff0import// BuildCTable builds a Huffman compression table from a precomputed symbol// histogram and installs it as the previous (reuse) table on s.//// After this call:// - EstimateSize/CanUseTable can probe the table against other histograms.// - Compress1X/Compress4X with Reuse = ReusePolicyMust will encode without// emitting a new table header.// - TransferCTable can hand the table to a sibling Scratch.//// count[i] is the number of occurrences of symbol i. The histogram must have// at least 2 distinct non-zero symbols; ErrUseRLE is returned for a single// symbol and an error is returned for an empty histogram.func ( *Scratch) ( *[256]uint32) error {if == nil {returnerrors.New("huff0: BuildCTable on nil Scratch") }if == nil {returnerrors.New("huff0: nil count passed to BuildCTable") }varerror , = .prepare(nil)if != nil {return } .count = *var , intvaruint16for , := range .count { += int()ifint() > { = int() }if != 0 { = uint16() + 1 } }if == 0 {returnerrors.New("huff0: empty histogram") }if < 2 || == {returnErrUseRLE }// huff0's internal rank table assumes total ≤ BlockSizeMax (it uses // highBit32(count+1) + 1 as a rank index into a fixed-size array). // Histograms summed across multiple blocks can exceed that; scale the // counts down preserving the distribution. Non-zero entries round up so // rare symbols stay representable.if > BlockSizeMax { := uint(0)for >> > BlockSizeMax { ++ } := uint32(1<<) - 1var , intfor , := range .count {if == 0 {continue } := ( + ) >> if == 0 { = 1 } .count[] = += int()ifint() > { = int() } } = = if == {returnErrUseRLE } } .symbolLen = .maxCount = .srcLen = if := .buildCTable(); != nil {return }ifcap(.prevTable) < len(.cTable) { .prevTable = make(cTable, 0, maxSymbolValue+1) } .prevTable = .prevTable[:len(.cTable)]copy(.prevTable, .cTable) .prevTableLog = .actualTableLog// Force the next Compress* to recount from real input. .clearCount = true .maxCount = 0returnnil}// EstimateSize returns an estimated compressed payload size in bytes for the// supplied histogram using the table currently stored in prevTable. It returns// -1 when the table cannot encode every non-zero symbol of hist (i.e. when// CanUseTable would return false). The estimate excludes the table header.func ( *Scratch) ( *[256]uint32) int {if == nil || == nil || len(.prevTable) == 0 {return -1 } := .prevTable := uint32(7)for , := range {if == 0 {continue }if >= len() || [].nBits == 0 {return -1 } += uint32([].nBits) * }returnint( >> 3)}// CanUseTable reports whether the table in prevTable can encode every// non-zero symbol present in hist.func ( *Scratch) ( *[256]uint32) bool {if == nil || == nil || len(.prevTable) == 0 {returnfalse } := .prevTablefor , := range {if == 0 {continue }if >= len() || [].nBits == 0 {returnfalse } }returntrue}// AppendTable serializes the table currently stored in prevTable (e.g. as// installed by BuildCTable or carried over from a previous Compress call)// into a self-delimiting zstd-style header and appends it to dst. The// returned slice can be parsed back by ReadTable.func ( *Scratch) ( []byte) ([]byte, error) {if == nil || len(.prevTable) == 0 {return , errors.New("huff0: AppendTable with empty table") }// cTable.write reads s.actualTableLog, s.symbolLen, s.huffWeight, s.fse // and writes into s.Out. Save/restore Out so we don't disturb in-flight // compression buffers. := .Out := .actualTableLog := .symbolLenif .fse == nil {// Lazily init in case AppendTable is called on a fresh Scratch.if , := .prepare(nil); != nil {return , } = .Out } .Out = .Out[:0] .actualTableLog = .prevTableLog .symbolLen = uint16(len(.prevTable))if := .prevTable.write(); != nil { .Out, .actualTableLog, .symbolLen = , , return , } = append(, .Out...) .Out, .actualTableLog, .symbolLen = , , return , nil}
The pages are generated with Goldsv0.8.4. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.