14
func Compress1X(in []byte, s *Scratch) (out []byte, reUsed bool, err error) {
15
s, err = s.prepare(in)
17
return nil, false, err
19
return compress(in, s, s.compress1X)
27
func Compress4X(in []byte, s *Scratch) (out []byte, reUsed bool, err error) {
28
s, err = s.prepare(in)
30
return nil, false, err
34
const parallelThreshold = 8 << 10
35
if len(in) < parallelThreshold || runtime.GOMAXPROCS(0) == 1 {
36
return compress(in, s, s.compress4X)
38
return compress(in, s, s.compress4Xp)
40
return compress(in, s, s.compress4X)
43
func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)) (out []byte, reUsed bool, err error) {
45
if s.Reuse == ReusePolicyNone {
46
s.prevTable = s.prevTable[:0]
50
maxCount := s.maxCount
53
maxCount, canReuse = s.countSimple(in)
55
canReuse = s.canUseTable(s.prevTable)
60
if s.WantLogLess > 0 {
61
wantSize -= wantSize >> s.WantLogLess
67
if maxCount >= len(in) {
68
if maxCount > len(in) {
69
return nil, false, fmt.Errorf("maxCount (%d) > length (%d)", maxCount, len(in))
72
return nil, false, ErrIncompressible
75
return nil, false, ErrUseRLE
77
if maxCount == 1 || maxCount < (len(in)>>7) {
79
return nil, false, ErrIncompressible
81
if s.Reuse == ReusePolicyMust && !canReuse {
83
return nil, false, ErrIncompressible
85
if (s.Reuse == ReusePolicyPrefer || s.Reuse == ReusePolicyMust) && canReuse {
87
keepTL := s.actualTableLog
88
s.cTable = s.prevTable
89
s.actualTableLog = s.prevTableLog
90
s.Out, err = compressor(in)
92
s.actualTableLog = keepTL
93
if err == nil && len(s.Out) < wantSize {
95
return s.Out, true, nil
97
if s.Reuse == ReusePolicyMust {
98
return nil, false, ErrIncompressible
101
s.prevTable = s.prevTable[:0]
105
err = s.buildCTable()
107
return nil, false, err
110
if false && !s.canUseTable(s.cTable) {
111
panic("invalid table generated")
114
if s.Reuse == ReusePolicyAllow && canReuse {
116
oldSize := s.prevTable.estimateSize(s.count[:s.symbolLen])
117
newSize := s.cTable.estimateSize(s.count[:s.symbolLen])
118
if oldSize <= hSize+newSize || hSize+12 >= wantSize {
120
keepTable := s.cTable
121
keepTL := s.actualTableLog
123
s.cTable = s.prevTable
124
s.actualTableLog = s.prevTableLog
125
s.Out, err = compressor(in)
129
s.actualTableLog = keepTL
131
return nil, false, err
133
if len(s.Out) >= wantSize {
134
return nil, false, ErrIncompressible
137
return s.Out, true, nil
142
err = s.cTable.write(s)
145
return nil, false, err
150
s.Out, err = compressor(in)
153
return nil, false, err
155
if len(s.Out) >= wantSize {
157
return nil, false, ErrIncompressible
160
s.prevTable, s.prevTableLog, s.cTable = s.cTable, s.actualTableLog, s.prevTable[:0]
161
s.OutData = s.Out[len(s.OutTable):]
162
return s.Out, false, nil
166
func EstimateSizes(in []byte, s *Scratch) (tableSz, dataSz, reuseSz int, err error) {
167
s, err = s.prepare(in)
173
tableSz, dataSz, reuseSz = -1, -1, -1
174
maxCount := s.maxCount
177
maxCount, canReuse = s.countSimple(in)
179
canReuse = s.canUseTable(s.prevTable)
184
if s.WantLogLess > 0 {
185
wantSize -= wantSize >> s.WantLogLess
191
if maxCount >= len(in) {
192
if maxCount > len(in) {
193
return 0, 0, 0, fmt.Errorf("maxCount (%d) > length (%d)", maxCount, len(in))
196
return 0, 0, 0, ErrIncompressible
199
return 0, 0, 0, ErrUseRLE
201
if maxCount == 1 || maxCount < (len(in)>>7) {
203
return 0, 0, 0, ErrIncompressible
207
err = s.buildCTable()
212
if false && !s.canUseTable(s.cTable) {
213
panic("invalid table generated")
216
tableSz, err = s.cTable.estTableSize(s)
221
reuseSz = s.prevTable.estimateSize(s.count[:s.symbolLen])
223
dataSz = s.cTable.estimateSize(s.count[:s.symbolLen])
226
return tableSz, dataSz, reuseSz, nil
229
func (s *Scratch) compress1X(src []byte) ([]byte, error) {
230
return s.compress1xDo(s.Out, src)
233
func (s *Scratch) compress1xDo(dst, src []byte) ([]byte, error) {
234
var bw = bitWriter{out: dst}
239
cTable := s.cTable[:256]
242
for i := len(src) & 3; i > 0; i-- {
243
bw.encSymbol(cTable, src[n+i-1])
246
if s.actualTableLog <= 8 {
247
for ; n >= 0; n -= 4 {
251
bw.encTwoSymbols(cTable, tmp[3], tmp[2])
252
bw.encTwoSymbols(cTable, tmp[1], tmp[0])
255
for ; n >= 0; n -= 4 {
259
bw.encTwoSymbols(cTable, tmp[3], tmp[2])
261
bw.encTwoSymbols(cTable, tmp[1], tmp[0])
270
func (s *Scratch) compress4X(src []byte) ([]byte, error) {
272
return nil, ErrIncompressible
274
segmentSize := (len(src) + 3) / 4
277
offsetIdx := len(s.Out)
278
s.Out = append(s.Out, sixZeros[:]...)
280
for i := 0; i < 4; i++ {
282
if len(toDo) > segmentSize {
283
toDo = toDo[:segmentSize]
285
src = src[len(toDo):]
289
s.Out, err = s.compress1xDo(s.Out, toDo)
293
if len(s.Out)-idx > math.MaxUint16 {
295
return nil, ErrIncompressible
300
length := len(s.Out) - idx
301
s.Out[i*2+offsetIdx] = byte(length)
302
s.Out[i*2+offsetIdx+1] = byte(length >> 8)
310
func (s *Scratch) compress4Xp(src []byte) ([]byte, error) {
312
return nil, ErrIncompressible
317
segmentSize := (len(src) + 3) / 4
318
var wg sync.WaitGroup
321
for i := 0; i < 4; i++ {
323
if len(toDo) > segmentSize {
324
toDo = toDo[:segmentSize]
326
src = src[len(toDo):]
330
s.tmpOut[i], errs[i] = s.compress1xDo(s.tmpOut[i][:0], toDo)
335
for i := 0; i < 4; i++ {
340
if len(o) > math.MaxUint16 {
342
return nil, ErrIncompressible
347
s.Out[i*2] = byte(len(o))
348
s.Out[i*2+1] = byte(len(o) >> 8)
352
s.Out = append(s.Out, o...)
360
func (s *Scratch) countSimple(in []byte) (max int, reuse bool) {
362
for _, v := range in {
366
if len(s.prevTable) > 0 {
367
for i, v := range s.count[:] {
372
s.symbolLen = uint16(i) + 1
373
if i >= len(s.prevTable) {
376
if s.prevTable[i].nBits == 0 {
384
for i, v := range s.count[:] {
389
s.symbolLen = uint16(i) + 1
395
func (s *Scratch) canUseTable(c cTable) bool {
396
if len(c) < int(s.symbolLen) {
399
for i, v := range s.count[:s.symbolLen] {
400
if v != 0 && c[i].nBits == 0 {
407
func (s *Scratch) validateTable(c cTable) bool {
408
if len(c) < int(s.symbolLen) {
411
for i, v := range s.count[:s.symbolLen] {
416
if c[i].nBits > s.actualTableLog {
425
func (s *Scratch) minTableLog() uint8 {
426
minBitsSrc := highBit32(uint32(s.br.remain())) + 1
427
minBitsSymbols := highBit32(uint32(s.symbolLen-1)) + 2
428
if minBitsSrc < minBitsSymbols {
429
return uint8(minBitsSrc)
431
return uint8(minBitsSymbols)
435
func (s *Scratch) optimalTableLog() {
436
tableLog := s.TableLog
437
minBits := s.minTableLog()
438
maxBitsSrc := uint8(highBit32(uint32(s.br.remain()-1))) - 1
439
if maxBitsSrc < tableLog {
441
tableLog = maxBitsSrc
443
if minBits > tableLog {
447
if tableLog < minTablelog {
448
tableLog = minTablelog
450
if tableLog > tableLogMax {
451
tableLog = tableLogMax
453
s.actualTableLog = tableLog
456
type cTableEntry struct {
462
const huffNodesMask = huffNodesLen - 1
464
func (s *Scratch) buildCTable() error {
467
if cap(s.cTable) < maxSymbolValue+1 {
468
s.cTable = make([]cTableEntry, s.symbolLen, maxSymbolValue+1)
470
s.cTable = s.cTable[:s.symbolLen]
471
for i := range s.cTable {
472
s.cTable[i] = cTableEntry{}
476
var startNode = int16(s.symbolLen)
477
nonNullRank := s.symbolLen - 1
480
huffNode := s.nodes[1 : huffNodesLen+1]
484
huffNode0 := s.nodes[0 : huffNodesLen+1]
486
for huffNode[nonNullRank].count == 0 {
490
lowS := int16(nonNullRank)
491
nodeRoot := nodeNb + lowS - 1
493
huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count
494
huffNode[lowS].parent, huffNode[lowS-1].parent = uint16(nodeNb), uint16(nodeNb)
497
for n := nodeNb; n <= nodeRoot; n++ {
498
huffNode[n].count = 1 << 30
501
huffNode0[0].count = 1 << 31
504
for nodeNb <= nodeRoot {
506
if huffNode0[lowS+1].count < huffNode0[lowN+1].count {
513
if huffNode0[lowS+1].count < huffNode0[lowN+1].count {
521
huffNode[nodeNb].count = huffNode0[n1+1].count + huffNode0[n2+1].count
522
huffNode0[n1+1].parent, huffNode0[n2+1].parent = uint16(nodeNb), uint16(nodeNb)
527
huffNode[nodeRoot].nbBits = 0
528
for n := nodeRoot - 1; n >= startNode; n-- {
529
huffNode[n].nbBits = huffNode[huffNode[n].parent].nbBits + 1
531
for n := uint16(0); n <= nonNullRank; n++ {
532
huffNode[n].nbBits = huffNode[huffNode[n].parent].nbBits + 1
534
s.actualTableLog = s.setMaxHeight(int(nonNullRank))
535
maxNbBits := s.actualTableLog
538
if maxNbBits > tableLogMax {
539
return fmt.Errorf("internal error: maxNbBits (%d) > tableLogMax (%d)", maxNbBits, tableLogMax)
541
var nbPerRank [tableLogMax + 1]uint16
542
var valPerRank [16]uint16
543
for _, v := range huffNode[:nonNullRank+1] {
544
nbPerRank[v.nbBits]++
549
for n := maxNbBits; n > 0; n-- {
558
for _, v := range huffNode[:nonNullRank+1] {
559
s.cTable[v.symbol].nBits = v.nbBits
563
t := s.cTable[:s.symbolLen]
564
for n, val := range t {
565
nbits := val.nBits & 15
566
v := valPerRank[nbits]
568
valPerRank[nbits] = v + 1
575
func (s *Scratch) huffSort() {
576
type rankPos struct {
582
nodes := s.nodes[:huffNodesLen+1]
584
nodes = nodes[1 : huffNodesLen+1]
588
for _, v := range s.count[:s.symbolLen] {
589
r := highBit32(v+1) & 31
593
const maxBitLength = 18 + 1
594
for n := maxBitLength; n > 0; n-- {
595
rank[n-1].base += rank[n].base
597
for n := range rank[:maxBitLength] {
598
rank[n].current = rank[n].base
600
for n, c := range s.count[:s.symbolLen] {
601
r := (highBit32(c+1) + 1) & 31
602
pos := rank[r].current
604
prev := nodes[(pos-1)&huffNodesMask]
605
for pos > rank[r].base && c > prev.count {
606
nodes[pos&huffNodesMask] = prev
608
prev = nodes[(pos-1)&huffNodesMask]
610
nodes[pos&huffNodesMask] = nodeElt{count: c, symbol: byte(n)}
614
func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
615
maxNbBits := s.actualTableLog
616
huffNode := s.nodes[1 : huffNodesLen+1]
619
largestBits := huffNode[lastNonNull].nbBits
622
if largestBits <= maxNbBits {
626
baseCost := int(1) << (largestBits - maxNbBits)
627
n := uint32(lastNonNull)
629
for huffNode[n].nbBits > maxNbBits {
630
totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits))
631
huffNode[n].nbBits = maxNbBits
636
for huffNode[n].nbBits == maxNbBits {
642
totalCost >>= largestBits - maxNbBits
646
const noSymbol = 0xF0F0F0F0
647
var rankLast [tableLogMax + 2]uint32
649
for i := range rankLast[:] {
650
rankLast[i] = noSymbol
655
currentNbBits := maxNbBits
656
for pos := int(n); pos >= 0; pos-- {
657
if huffNode[pos].nbBits >= currentNbBits {
660
currentNbBits = huffNode[pos].nbBits
661
rankLast[maxNbBits-currentNbBits] = uint32(pos)
666
nBitsToDecrease := uint8(highBit32(uint32(totalCost))) + 1
668
for ; nBitsToDecrease > 1; nBitsToDecrease-- {
669
highPos := rankLast[nBitsToDecrease]
670
lowPos := rankLast[nBitsToDecrease-1]
671
if highPos == noSymbol {
674
if lowPos == noSymbol {
677
highTotal := huffNode[highPos].count
678
lowTotal := 2 * huffNode[lowPos].count
679
if highTotal <= lowTotal {
686
for (nBitsToDecrease <= tableLogMax) && (rankLast[nBitsToDecrease] == noSymbol) {
689
totalCost -= 1 << (nBitsToDecrease - 1)
690
if rankLast[nBitsToDecrease-1] == noSymbol {
692
rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]
694
huffNode[rankLast[nBitsToDecrease]].nbBits++
695
if rankLast[nBitsToDecrease] == 0 {
697
rankLast[nBitsToDecrease] = noSymbol
699
rankLast[nBitsToDecrease]--
700
if huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease {
701
rankLast[nBitsToDecrease] = noSymbol
707
if rankLast[1] == noSymbol {
708
for huffNode[n].nbBits == maxNbBits {
711
huffNode[n+1].nbBits--
716
huffNode[rankLast[1]+1].nbBits--