huff0.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Package huff0 provides fast huffman encoding as used in zstd.
  2. //
  3. // See README.md at https://github.com/klauspost/compress/tree/master/huff0 for details.
  4. package huff0
  5. import (
  6. "errors"
  7. "fmt"
  8. "math"
  9. "math/bits"
  10. "github.com/klauspost/compress/fse"
  11. )
  12. const (
  13. maxSymbolValue = 255
  14. // zstandard limits tablelog to 11, see:
  15. // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#huffman-tree-description
  16. tableLogMax = 11
  17. tableLogDefault = 11
  18. minTablelog = 5
  19. huffNodesLen = 512
  20. // BlockSizeMax is maximum input size for a single block uncompressed.
  21. BlockSizeMax = 1<<18 - 1
  22. )
  23. var (
  24. // ErrIncompressible is returned when input is judged to be too hard to compress.
  25. ErrIncompressible = errors.New("input is not compressible")
  26. // ErrUseRLE is returned from the compressor when the input is a single byte value repeated.
  27. ErrUseRLE = errors.New("input is single value repeated")
  28. // ErrTooBig is return if input is too large for a single block.
  29. ErrTooBig = errors.New("input too big")
  30. // ErrMaxDecodedSizeExceeded is return if input is too large for a single block.
  31. ErrMaxDecodedSizeExceeded = errors.New("maximum output size exceeded")
  32. )
  33. type ReusePolicy uint8
  34. const (
  35. // ReusePolicyAllow will allow reuse if it produces smaller output.
  36. ReusePolicyAllow ReusePolicy = iota
  37. // ReusePolicyPrefer will re-use aggressively if possible.
  38. // This will not check if a new table will produce smaller output,
  39. // except if the current table is impossible to use or
  40. // compressed output is bigger than input.
  41. ReusePolicyPrefer
  42. // ReusePolicyNone will disable re-use of tables.
  43. // This is slightly faster than ReusePolicyAllow but may produce larger output.
  44. ReusePolicyNone
  45. )
  46. type Scratch struct {
  47. count [maxSymbolValue + 1]uint32
  48. // Per block parameters.
  49. // These can be used to override compression parameters of the block.
  50. // Do not touch, unless you know what you are doing.
  51. // Out is output buffer.
  52. // If the scratch is re-used before the caller is done processing the output,
  53. // set this field to nil.
  54. // Otherwise the output buffer will be re-used for next Compression/Decompression step
  55. // and allocation will be avoided.
  56. Out []byte
  57. // OutTable will contain the table data only, if a new table has been generated.
  58. // Slice of the returned data.
  59. OutTable []byte
  60. // OutData will contain the compressed data.
  61. // Slice of the returned data.
  62. OutData []byte
  63. // MaxDecodedSize will set the maximum allowed output size.
  64. // This value will automatically be set to BlockSizeMax if not set.
  65. // Decoders will return ErrMaxDecodedSizeExceeded is this limit is exceeded.
  66. MaxDecodedSize int
  67. br byteReader
  68. // MaxSymbolValue will override the maximum symbol value of the next block.
  69. MaxSymbolValue uint8
  70. // TableLog will attempt to override the tablelog for the next block.
  71. // Must be <= 11 and >= 5.
  72. TableLog uint8
  73. // Reuse will specify the reuse policy
  74. Reuse ReusePolicy
  75. // WantLogLess allows to specify a log 2 reduction that should at least be achieved,
  76. // otherwise the block will be returned as incompressible.
  77. // The reduction should then at least be (input size >> WantLogLess)
  78. // If WantLogLess == 0 any improvement will do.
  79. WantLogLess uint8
  80. symbolLen uint16 // Length of active part of the symbol table.
  81. maxCount int // count of the most probable symbol
  82. clearCount bool // clear count
  83. actualTableLog uint8 // Selected tablelog.
  84. prevTableLog uint8 // Tablelog for previous table
  85. prevTable cTable // Table used for previous compression.
  86. cTable cTable // compression table
  87. dt dTable // decompression table
  88. nodes []nodeElt
  89. tmpOut [4][]byte
  90. fse *fse.Scratch
  91. huffWeight [maxSymbolValue + 1]byte
  92. }
  93. func (s *Scratch) prepare(in []byte) (*Scratch, error) {
  94. if len(in) > BlockSizeMax {
  95. return nil, ErrTooBig
  96. }
  97. if s == nil {
  98. s = &Scratch{}
  99. }
  100. if s.MaxSymbolValue == 0 {
  101. s.MaxSymbolValue = maxSymbolValue
  102. }
  103. if s.TableLog == 0 {
  104. s.TableLog = tableLogDefault
  105. }
  106. if s.TableLog > tableLogMax || s.TableLog < minTablelog {
  107. return nil, fmt.Errorf(" invalid tableLog %d (%d -> %d)", s.TableLog, minTablelog, tableLogMax)
  108. }
  109. if s.MaxDecodedSize <= 0 || s.MaxDecodedSize > BlockSizeMax {
  110. s.MaxDecodedSize = BlockSizeMax
  111. }
  112. if s.clearCount && s.maxCount == 0 {
  113. for i := range s.count {
  114. s.count[i] = 0
  115. }
  116. s.clearCount = false
  117. }
  118. if cap(s.Out) == 0 {
  119. s.Out = make([]byte, 0, len(in))
  120. }
  121. s.Out = s.Out[:0]
  122. s.OutTable = nil
  123. s.OutData = nil
  124. if cap(s.nodes) < huffNodesLen+1 {
  125. s.nodes = make([]nodeElt, 0, huffNodesLen+1)
  126. }
  127. s.nodes = s.nodes[:0]
  128. if s.fse == nil {
  129. s.fse = &fse.Scratch{}
  130. }
  131. s.br.init(in)
  132. return s, nil
  133. }
  134. type cTable []cTableEntry
  135. func (c cTable) write(s *Scratch) error {
  136. var (
  137. // precomputed conversion table
  138. bitsToWeight [tableLogMax + 1]byte
  139. huffLog = s.actualTableLog
  140. // last weight is not saved.
  141. maxSymbolValue = uint8(s.symbolLen - 1)
  142. huffWeight = s.huffWeight[:256]
  143. )
  144. const (
  145. maxFSETableLog = 6
  146. )
  147. // convert to weight
  148. bitsToWeight[0] = 0
  149. for n := uint8(1); n < huffLog+1; n++ {
  150. bitsToWeight[n] = huffLog + 1 - n
  151. }
  152. // Acquire histogram for FSE.
  153. hist := s.fse.Histogram()
  154. hist = hist[:256]
  155. for i := range hist[:16] {
  156. hist[i] = 0
  157. }
  158. for n := uint8(0); n < maxSymbolValue; n++ {
  159. v := bitsToWeight[c[n].nBits] & 15
  160. huffWeight[n] = v
  161. hist[v]++
  162. }
  163. // FSE compress if feasible.
  164. if maxSymbolValue >= 2 {
  165. huffMaxCnt := uint32(0)
  166. huffMax := uint8(0)
  167. for i, v := range hist[:16] {
  168. if v == 0 {
  169. continue
  170. }
  171. huffMax = byte(i)
  172. if v > huffMaxCnt {
  173. huffMaxCnt = v
  174. }
  175. }
  176. s.fse.HistogramFinished(huffMax, int(huffMaxCnt))
  177. s.fse.TableLog = maxFSETableLog
  178. b, err := fse.Compress(huffWeight[:maxSymbolValue], s.fse)
  179. if err == nil && len(b) < int(s.symbolLen>>1) {
  180. s.Out = append(s.Out, uint8(len(b)))
  181. s.Out = append(s.Out, b...)
  182. return nil
  183. }
  184. // Unable to compress (RLE/uncompressible)
  185. }
  186. // write raw values as 4-bits (max : 15)
  187. if maxSymbolValue > (256 - 128) {
  188. // should not happen : likely means source cannot be compressed
  189. return ErrIncompressible
  190. }
  191. op := s.Out
  192. // special case, pack weights 4 bits/weight.
  193. op = append(op, 128|(maxSymbolValue-1))
  194. // be sure it doesn't cause msan issue in final combination
  195. huffWeight[maxSymbolValue] = 0
  196. for n := uint16(0); n < uint16(maxSymbolValue); n += 2 {
  197. op = append(op, (huffWeight[n]<<4)|huffWeight[n+1])
  198. }
  199. s.Out = op
  200. return nil
  201. }
  202. // estimateSize returns the estimated size in bytes of the input represented in the
  203. // histogram supplied.
  204. func (c cTable) estimateSize(hist []uint32) int {
  205. nbBits := uint32(7)
  206. for i, v := range c[:len(hist)] {
  207. nbBits += uint32(v.nBits) * hist[i]
  208. }
  209. return int(nbBits >> 3)
  210. }
  211. // minSize returns the minimum possible size considering the shannon limit.
  212. func (s *Scratch) minSize(total int) int {
  213. nbBits := float64(7)
  214. fTotal := float64(total)
  215. for _, v := range s.count[:s.symbolLen] {
  216. n := float64(v)
  217. if n > 0 {
  218. nbBits += math.Log2(fTotal/n) * n
  219. }
  220. }
  221. return int(nbBits) >> 3
  222. }
  223. func highBit32(val uint32) (n uint32) {
  224. return uint32(bits.Len32(val) - 1)
  225. }