...
1 package zstd
2
3 import (
4 "errors"
5 "fmt"
6 "math"
7 "math/bits"
8 "runtime"
9 "strings"
10 )
11
12
13 type EOption func(*encoderOptions) error
14
15
16 type encoderOptions struct {
17 concurrent int
18 level EncoderLevel
19 single *bool
20 pad int
21 blockSize int
22 windowSize int
23 crc bool
24 fullZero bool
25 noEntropy bool
26 allLitEntropy bool
27 customWindow bool
28 customALEntropy bool
29 customBlockSize bool
30 lowMem bool
31 dict *dict
32 }
33
34 func (o *encoderOptions) setDefault() {
35 *o = encoderOptions{
36 concurrent: runtime.GOMAXPROCS(0),
37 crc: true,
38 single: nil,
39 blockSize: maxCompressedBlockSize,
40 windowSize: 8 << 20,
41 level: SpeedDefault,
42 allLitEntropy: false,
43 lowMem: false,
44 }
45 }
46
47
48 func (o encoderOptions) encoder() encoder {
49 switch o.level {
50 case SpeedFastest:
51 if o.dict != nil {
52 return &fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
53 }
54 return &fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
55
56 case SpeedDefault:
57 if o.dict != nil {
58 return &doubleFastEncoderDict{fastEncoderDict: fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}}
59 }
60 return &doubleFastEncoder{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
61 case SpeedBetterCompression:
62 if o.dict != nil {
63 return &betterFastEncoderDict{betterFastEncoder: betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
64 }
65 return &betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
66 case SpeedBestCompression:
67 return &bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
68 }
69 panic("unknown compression level")
70 }
71
72
73
74 func WithEncoderCRC(b bool) EOption {
75 return func(o *encoderOptions) error { o.crc = b; return nil }
76 }
77
78
79
80
81
82
83 func WithEncoderConcurrency(n int) EOption {
84 return func(o *encoderOptions) error {
85 if n <= 0 {
86 return fmt.Errorf("concurrency must be at least 1")
87 }
88 o.concurrent = n
89 return nil
90 }
91 }
92
93
94
95
96
97
98 func WithWindowSize(n int) EOption {
99 return func(o *encoderOptions) error {
100 switch {
101 case n < MinWindowSize:
102 return fmt.Errorf("window size must be at least %d", MinWindowSize)
103 case n > MaxWindowSize:
104 return fmt.Errorf("window size must be at most %d", MaxWindowSize)
105 case (n & (n - 1)) != 0:
106 return errors.New("window size must be a power of 2")
107 }
108
109 o.windowSize = n
110 o.customWindow = true
111 if o.blockSize > o.windowSize {
112 o.blockSize = o.windowSize
113 o.customBlockSize = true
114 }
115 return nil
116 }
117 }
118
119
120
121
122
123
124
125 func WithEncoderPadding(n int) EOption {
126 return func(o *encoderOptions) error {
127 if n <= 0 {
128 return fmt.Errorf("padding must be at least 1")
129 }
130
131 if n == 1 {
132 n = 0
133 }
134 if n > 1<<30 {
135 return fmt.Errorf("padding must less than 1GB (1<<30 bytes) ")
136 }
137 o.pad = n
138 return nil
139 }
140 }
141
142
143
144
145
146 type EncoderLevel int
147
148 const (
149 speedNotSet EncoderLevel = iota
150
151
152
153 SpeedFastest
154
155
156
157 SpeedDefault
158
159
160
161
162 SpeedBetterCompression
163
164
165
166 SpeedBestCompression
167
168
169
170 speedLast
171 )
172
173
174
175
176 func EncoderLevelFromString(s string) (bool, EncoderLevel) {
177 for l := speedNotSet + 1; l < speedLast; l++ {
178 if strings.EqualFold(s, l.String()) {
179 return true, l
180 }
181 }
182 return false, SpeedDefault
183 }
184
185
186
187
188 func EncoderLevelFromZstd(level int) EncoderLevel {
189 switch {
190 case level < 3:
191 return SpeedFastest
192 case level >= 3 && level < 6:
193 return SpeedDefault
194 case level >= 6 && level < 10:
195 return SpeedBetterCompression
196 default:
197 return SpeedBestCompression
198 }
199 }
200
201
202 func (e EncoderLevel) String() string {
203 switch e {
204 case SpeedFastest:
205 return "fastest"
206 case SpeedDefault:
207 return "default"
208 case SpeedBetterCompression:
209 return "better"
210 case SpeedBestCompression:
211 return "best"
212 default:
213 return "invalid"
214 }
215 }
216
217
218 func WithEncoderLevel(l EncoderLevel) EOption {
219 return func(o *encoderOptions) error {
220 switch {
221 case l <= speedNotSet || l >= speedLast:
222 return fmt.Errorf("unknown encoder level")
223 }
224 o.level = l
225 if !o.customWindow {
226 switch o.level {
227 case SpeedFastest:
228 o.windowSize = 4 << 20
229 if !o.customBlockSize {
230 o.blockSize = 1 << 16
231 }
232 case SpeedDefault:
233 o.windowSize = 8 << 20
234 case SpeedBetterCompression:
235 o.windowSize = 8 << 20
236 case SpeedBestCompression:
237 o.windowSize = 8 << 20
238 }
239 }
240 if !o.customALEntropy {
241 o.allLitEntropy = l > SpeedDefault
242 }
243
244 return nil
245 }
246 }
247
248
249
250
251 func WithZeroFrames(b bool) EOption {
252 return func(o *encoderOptions) error {
253 o.fullZero = b
254 return nil
255 }
256 }
257
258
259
260
261
262 func WithAllLitEntropyCompression(b bool) EOption {
263 return func(o *encoderOptions) error {
264 o.customALEntropy = true
265 o.allLitEntropy = b
266 return nil
267 }
268 }
269
270
271
272
273 func WithNoEntropyCompression(b bool) EOption {
274 return func(o *encoderOptions) error {
275 o.noEntropy = b
276 return nil
277 }
278 }
279
280
281
282
283
284
285
286
287
288
289
290 func WithSingleSegment(b bool) EOption {
291 return func(o *encoderOptions) error {
292 o.single = &b
293 return nil
294 }
295 }
296
297
298
299
300
301 func WithLowerEncoderMem(b bool) EOption {
302 return func(o *encoderOptions) error {
303 o.lowMem = b
304 return nil
305 }
306 }
307
308
309
310
311
312
313
314
315
316 func WithEncoderDict(dict []byte) EOption {
317 return func(o *encoderOptions) error {
318 d, err := loadDict(dict)
319 if err != nil {
320 return err
321 }
322 o.dict = d
323 return nil
324 }
325 }
326
327
328
329
330
331 func WithEncoderDictRaw(id uint32, content []byte) EOption {
332 return func(o *encoderOptions) error {
333 if bits.UintSize > 32 && uint(len(content)) > dictMaxLength {
334 return fmt.Errorf("dictionary of size %d > 2GiB too large", len(content))
335 }
336 o.dict = &dict{id: id, content: content, offsets: [3]int{1, 4, 8}}
337 return nil
338 }
339 }
340
View as plain text