options.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. package lz4
  2. import (
  3. "fmt"
  4. "reflect"
  5. "runtime"
  6. "sync"
  7. )
  8. //go:generate go run golang.org/x/tools/cmd/stringer -type=BlockSize,CompressionLevel -output options_gen.go
  9. type (
  10. Applier interface {
  11. Apply(...Option) error
  12. private()
  13. }
  14. // Option defines the parameters to setup an LZ4 Writer or Reader.
  15. Option func(Applier) error
  16. )
  17. func (o Option) String() string {
  18. //TODO proper naming of options
  19. return reflect.TypeOf(o).String()
  20. }
  21. // Default options.
  22. var (
  23. defaultBlockSizeOption = BlockSizeOption(Block4Mb)
  24. defaultChecksumOption = ChecksumOption(true)
  25. defaultConcurrency = ConcurrencyOption(1)
  26. defaultOnBlockDone = OnBlockDoneOption(nil)
  27. )
  28. const (
  29. Block64Kb BlockSize = 1 << (16 + iota*2)
  30. Block256Kb
  31. Block1Mb
  32. Block4Mb
  33. )
  34. var (
  35. blockPool64K = sync.Pool{New: func() interface{} { return make([]byte, Block64Kb) }}
  36. blockPool256K = sync.Pool{New: func() interface{} { return make([]byte, Block256Kb) }}
  37. blockPool1M = sync.Pool{New: func() interface{} { return make([]byte, Block1Mb) }}
  38. blockPool4M = sync.Pool{New: func() interface{} { return make([]byte, Block4Mb) }}
  39. )
  40. // BlockSizeIndex defines the size of the blocks to be compressed.
  41. type BlockSize uint32
  42. func (b BlockSize) isValid() bool {
  43. return b.index() > 0
  44. }
  45. func (b BlockSize) index() BlockSizeIndex {
  46. switch b {
  47. case Block64Kb:
  48. return 4
  49. case Block256Kb:
  50. return 5
  51. case Block1Mb:
  52. return 6
  53. case Block4Mb:
  54. return 7
  55. }
  56. return 0
  57. }
  58. type BlockSizeIndex uint8
  59. func (b BlockSizeIndex) get() []byte {
  60. var buf interface{}
  61. switch b {
  62. case 4:
  63. buf = blockPool64K.Get()
  64. case 5:
  65. buf = blockPool256K.Get()
  66. case 6:
  67. buf = blockPool1M.Get()
  68. case 7:
  69. buf = blockPool4M.Get()
  70. }
  71. return buf.([]byte)
  72. }
  73. func (b BlockSizeIndex) put(buf []byte) {
  74. switch b {
  75. case 4:
  76. blockPool64K.Put(buf)
  77. case 5:
  78. blockPool256K.Put(buf)
  79. case 6:
  80. blockPool1M.Put(buf)
  81. case 7:
  82. blockPool4M.Put(buf)
  83. }
  84. }
  85. // BlockSizeOption defines the maximum size of compressed blocks (default=Block4Mb).
  86. func BlockSizeOption(size BlockSize) Option {
  87. return func(a Applier) error {
  88. w, ok := a.(*Writer)
  89. if !ok {
  90. return ErrOptionNotApplicable
  91. }
  92. if !size.isValid() {
  93. return fmt.Errorf("%w: %d", ErrOptionInvalidBlockSize, size)
  94. }
  95. w.frame.Descriptor.Flags.BlockSizeIndexSet(size.index())
  96. return nil
  97. }
  98. }
  99. // BlockChecksumOption enables or disables block checksum (default=false).
  100. func BlockChecksumOption(flag bool) Option {
  101. return func(a Applier) error {
  102. w, ok := a.(*Writer)
  103. if !ok {
  104. return ErrOptionNotApplicable
  105. }
  106. w.frame.Descriptor.Flags.BlockChecksumSet(flag)
  107. return nil
  108. }
  109. }
  110. // ChecksumOption enables/disables all blocks checksum (default=true).
  111. func ChecksumOption(flag bool) Option {
  112. return func(a Applier) error {
  113. w, ok := a.(*Writer)
  114. if !ok {
  115. return ErrOptionNotApplicable
  116. }
  117. w.frame.Descriptor.Flags.ContentChecksumSet(flag)
  118. return nil
  119. }
  120. }
  121. // SizeOption sets the size of the original uncompressed data (default=0).
  122. func SizeOption(size uint64) Option {
  123. return func(a Applier) error {
  124. w, ok := a.(*Writer)
  125. if !ok {
  126. return ErrOptionNotApplicable
  127. }
  128. w.frame.Descriptor.Flags.SizeSet(size > 0)
  129. w.frame.Descriptor.ContentSize = size
  130. return nil
  131. }
  132. }
  133. // ConcurrencyOption sets the number of go routines used for compression.
  134. // If n<0, then the output of runtime.GOMAXPROCS(0) is used.
  135. func ConcurrencyOption(n int) Option {
  136. return func(a Applier) error {
  137. w, ok := a.(*Writer)
  138. if !ok {
  139. return ErrOptionNotApplicable
  140. }
  141. switch n {
  142. case 0, 1:
  143. default:
  144. if n < 0 {
  145. n = runtime.GOMAXPROCS(0)
  146. }
  147. }
  148. w.num = n
  149. return nil
  150. }
  151. }
  152. // CompressionLevel defines the level of compression to use. The higher the better, but slower, compression.
  153. type CompressionLevel uint32
  154. const (
  155. Fast CompressionLevel = 0
  156. Level1 CompressionLevel = 1 << (8 + iota)
  157. Level2
  158. Level3
  159. Level4
  160. Level5
  161. Level6
  162. Level7
  163. Level8
  164. Level9
  165. )
  166. // CompressionLevelOption defines the compression level (default=Fast).
  167. func CompressionLevelOption(level CompressionLevel) Option {
  168. return func(a Applier) error {
  169. w, ok := a.(*Writer)
  170. if !ok {
  171. return ErrOptionNotApplicable
  172. }
  173. switch level {
  174. case Fast, Level1, Level2, Level3, Level4, Level5, Level6, Level7, Level8, Level9:
  175. default:
  176. return fmt.Errorf("%w: %d", ErrOptionInvalidCompressionLevel, level)
  177. }
  178. w.level = level
  179. return nil
  180. }
  181. }
  182. func onBlockDone(int) {}
  183. // OnBlockDoneOption is triggered
  184. func OnBlockDoneOption(handler func(size int)) Option {
  185. if handler == nil {
  186. handler = onBlockDone
  187. }
  188. return func(a Applier) error {
  189. if r, ok := a.(*Reader); ok {
  190. r.handler = handler
  191. return nil
  192. }
  193. if w, ok := a.(*Writer); ok {
  194. w.handler = handler
  195. return nil
  196. }
  197. return ErrOptionNotApplicable
  198. }
  199. }