10
dFastLongTableBits = 17
11
dFastLongTableSize = 1 << dFastLongTableBits
12
dFastLongTableMask = dFastLongTableSize - 1
15
dLongTableShardCnt = 1 << (dFastLongTableBits - dictShardBits)
16
dLongTableShardSize = dFastLongTableSize / tableShardCnt
18
dFastShortTableBits = tableBits
19
dFastShortTableSize = 1 << dFastShortTableBits
20
dFastShortTableMask = dFastShortTableSize - 1
25
type doubleFastEncoder struct {
27
longTable [dFastLongTableSize]tableEntry
30
type doubleFastEncoderDict struct {
32
longTable [dFastLongTableSize]tableEntry
33
dictLongTable []tableEntry
34
longTableShardDirty [dLongTableShardCnt]bool
38
func (e *doubleFastEncoder) Encode(blk *blockEnc, src []byte) {
43
minNonLiteralBlockSize = 16
47
for e.cur >= bufferReset {
49
for i := range e.table[:] {
50
e.table[i] = tableEntry{}
52
for i := range e.longTable[:] {
53
e.longTable[i] = tableEntry{}
59
minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
60
for i := range e.table[:] {
61
v := e.table[i].offset
65
v = v - e.cur + e.maxMatchOff
69
for i := range e.longTable[:] {
70
v := e.longTable[i].offset
74
v = v - e.cur + e.maxMatchOff
76
e.longTable[i].offset = v
84
if len(src) < minNonLiteralBlockSize {
85
blk.extraLits = len(src)
86
blk.literals = blk.literals[:len(src)]
87
copy(blk.literals, src)
93
sLimit := int32(len(src)) - inputMargin
98
const kSearchStrength = 8
102
cv := load6432(src, s)
105
offset1 := int32(blk.recentOffsets[0])
106
offset2 := int32(blk.recentOffsets[1])
108
addLiterals := func(s *seq, until int32) {
109
if until == nextEmit {
112
blk.literals = append(blk.literals, src[nextEmit:until]...)
113
s.litLen = uint32(until - nextEmit)
116
println("recent offsets:", blk.recentOffsets)
123
canRepeat := len(blk.sequences) > 2
126
if debugAsserts && canRepeat && offset1 == 0 {
127
panic("offset0 was 0")
130
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
131
nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
132
candidateL := e.longTable[nextHashL]
133
candidateS := e.table[nextHashS]
136
repIndex := s - offset1 + repOff
137
entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
138
e.longTable[nextHashL] = entry
139
e.table[nextHashS] = entry
142
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
145
lenght := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
147
seq.matchLen = uint32(lenght - zstdMinMatch)
154
startLimit := nextEmit + 1
156
tMin := s - e.maxMatchOff
160
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
165
addLiterals(&seq, start)
170
println("repeat sequence", seq, "next s:", s)
172
blk.sequences = append(blk.sequences, seq)
177
println("repeat ended", s, lenght)
182
cv = load6432(src, s)
187
coffsetL := s - (candidateL.offset - e.cur)
188
coffsetS := s - (candidateS.offset - e.cur)
191
if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
195
t = candidateL.offset - e.cur
196
if debugAsserts && s <= t {
197
panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
199
if debugAsserts && s-t > e.maxMatchOff {
200
panic("s - t >e.maxMatchOff")
203
println("long match")
209
if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
213
cv := load6432(src, s+checkAt)
214
nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen)
215
candidateL = e.longTable[nextHashL]
216
coffsetL = s - (candidateL.offset - e.cur) + checkAt
219
e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)}
220
if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
224
t = candidateL.offset - e.cur
227
println("long match (after short)")
232
t = candidateS.offset - e.cur
233
if debugAsserts && s <= t {
234
panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
236
if debugAsserts && s-t > e.maxMatchOff {
237
panic("s - t >e.maxMatchOff")
239
if debugAsserts && t < 0 {
243
println("short match")
249
s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
253
cv = load6432(src, s)
261
if debugAsserts && s <= t {
262
panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
265
if debugAsserts && canRepeat && int(offset1) > len(src) {
266
panic("invalid offset")
270
l := e.matchlen(s+4, t+4, src) + 4
273
tMin := s - e.maxMatchOff
277
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
285
seq.litLen = uint32(s - nextEmit)
286
seq.matchLen = uint32(l - zstdMinMatch)
288
blk.literals = append(blk.literals, src[nextEmit:s]...)
290
seq.offset = uint32(s-t) + 3
293
println("sequence", seq, "next s:", s)
295
blk.sequences = append(blk.sequences, seq)
306
cv0 := load6432(src, index0)
307
cv1 := load6432(src, index1)
308
te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
309
te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
310
e.longTable[hashLen(cv0, dFastLongTableBits, dFastLongLen)] = te0
311
e.longTable[hashLen(cv1, dFastLongTableBits, dFastLongLen)] = te1
316
te0.val = uint32(cv0)
317
te1.val = uint32(cv1)
318
e.table[hashLen(cv0, dFastShortTableBits, dFastShortLen)] = te0
319
e.table[hashLen(cv1, dFastShortTableBits, dFastShortLen)] = te1
321
cv = load6432(src, s)
330
if load3232(src, o2) != uint32(cv) {
336
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
337
nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
341
l := 4 + e.matchlen(s+4, o2+4, src)
343
entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
344
e.longTable[nextHashL] = entry
345
e.table[nextHashS] = entry
346
seq.matchLen = uint32(l) - zstdMinMatch
354
println("sequence", seq, "next s:", s)
356
blk.sequences = append(blk.sequences, seq)
359
offset1, offset2 = offset2, offset1
364
cv = load6432(src, s)
368
if int(nextEmit) < len(src) {
369
blk.literals = append(blk.literals, src[nextEmit:]...)
370
blk.extraLits = len(src) - int(nextEmit)
372
blk.recentOffsets[0] = uint32(offset1)
373
blk.recentOffsets[1] = uint32(offset2)
375
println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
382
func (e *doubleFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
387
minNonLiteralBlockSize = 16
391
if e.cur >= bufferReset {
392
for i := range e.table[:] {
393
e.table[i] = tableEntry{}
395
for i := range e.longTable[:] {
396
e.longTable[i] = tableEntry{}
398
e.cur = e.maxMatchOff
403
if len(src) < minNonLiteralBlockSize {
404
blk.extraLits = len(src)
405
blk.literals = blk.literals[:len(src)]
406
copy(blk.literals, src)
411
sLimit := int32(len(src)) - inputMargin
416
const kSearchStrength = 8
420
cv := load6432(src, s)
423
offset1 := int32(blk.recentOffsets[0])
424
offset2 := int32(blk.recentOffsets[1])
426
addLiterals := func(s *seq, until int32) {
427
if until == nextEmit {
430
blk.literals = append(blk.literals, src[nextEmit:until]...)
431
s.litLen = uint32(until - nextEmit)
434
println("recent offsets:", blk.recentOffsets)
442
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
443
nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
444
candidateL := e.longTable[nextHashL]
445
candidateS := e.table[nextHashS]
448
repIndex := s - offset1 + repOff
449
entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
450
e.longTable[nextHashL] = entry
451
e.table[nextHashS] = entry
453
if len(blk.sequences) > 2 {
454
if load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
458
length := 4 + int32(matchLen(src[s+4+repOff:], src[repIndex+4:]))
460
seq.matchLen = uint32(length - zstdMinMatch)
467
startLimit := nextEmit + 1
469
tMin := s - e.maxMatchOff
473
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] {
478
addLiterals(&seq, start)
483
println("repeat sequence", seq, "next s:", s)
485
blk.sequences = append(blk.sequences, seq)
490
println("repeat ended", s, length)
495
cv = load6432(src, s)
500
coffsetL := s - (candidateL.offset - e.cur)
501
coffsetS := s - (candidateS.offset - e.cur)
504
if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
508
t = candidateL.offset - e.cur
509
if debugAsserts && s <= t {
510
panic(fmt.Sprintf("s (%d) <= t (%d). cur: %d", s, t, e.cur))
512
if debugAsserts && s-t > e.maxMatchOff {
513
panic("s - t >e.maxMatchOff")
516
println("long match")
522
if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
526
cv := load6432(src, s+checkAt)
527
nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen)
528
candidateL = e.longTable[nextHashL]
529
coffsetL = s - (candidateL.offset - e.cur) + checkAt
532
e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)}
533
if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
537
t = candidateL.offset - e.cur
540
println("long match (after short)")
545
t = candidateS.offset - e.cur
546
if debugAsserts && s <= t {
547
panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
549
if debugAsserts && s-t > e.maxMatchOff {
550
panic("s - t >e.maxMatchOff")
552
if debugAsserts && t < 0 {
556
println("short match")
562
s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
566
cv = load6432(src, s)
574
if debugAsserts && s <= t {
575
panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
580
l := int32(matchLen(src[s+4:], src[t+4:])) + 4
583
tMin := s - e.maxMatchOff
587
for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
595
seq.litLen = uint32(s - nextEmit)
596
seq.matchLen = uint32(l - zstdMinMatch)
598
blk.literals = append(blk.literals, src[nextEmit:s]...)
600
seq.offset = uint32(s-t) + 3
603
println("sequence", seq, "next s:", s)
605
blk.sequences = append(blk.sequences, seq)
616
cv0 := load6432(src, index0)
617
cv1 := load6432(src, index1)
618
te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
619
te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
620
e.longTable[hashLen(cv0, dFastLongTableBits, dFastLongLen)] = te0
621
e.longTable[hashLen(cv1, dFastLongTableBits, dFastLongLen)] = te1
626
te0.val = uint32(cv0)
627
te1.val = uint32(cv1)
628
e.table[hashLen(cv0, dFastShortTableBits, dFastShortLen)] = te0
629
e.table[hashLen(cv1, dFastShortTableBits, dFastShortLen)] = te1
631
cv = load6432(src, s)
633
if len(blk.sequences) <= 2 {
640
if load3232(src, o2) != uint32(cv) {
646
nextHashS := hashLen(cv1>>8, dFastShortTableBits, dFastShortLen)
647
nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
652
l := 4 + int32(matchLen(src[s+4:], src[o2+4:]))
654
entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
655
e.longTable[nextHashL] = entry
656
e.table[nextHashS] = entry
657
seq.matchLen = uint32(l) - zstdMinMatch
665
println("sequence", seq, "next s:", s)
667
blk.sequences = append(blk.sequences, seq)
670
offset1, offset2 = offset2, offset1
675
cv = load6432(src, s)
679
if int(nextEmit) < len(src) {
680
blk.literals = append(blk.literals, src[nextEmit:]...)
681
blk.extraLits = len(src) - int(nextEmit)
684
println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
688
if e.cur < bufferReset {
689
e.cur += int32(len(src))
694
func (e *doubleFastEncoderDict) Encode(blk *blockEnc, src []byte) {
699
minNonLiteralBlockSize = 16
703
for e.cur >= bufferReset {
704
if len(e.hist) == 0 {
705
for i := range e.table[:] {
706
e.table[i] = tableEntry{}
708
for i := range e.longTable[:] {
709
e.longTable[i] = tableEntry{}
711
e.markAllShardsDirty()
712
e.cur = e.maxMatchOff
716
minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
717
for i := range e.table[:] {
718
v := e.table[i].offset
722
v = v - e.cur + e.maxMatchOff
724
e.table[i].offset = v
726
for i := range e.longTable[:] {
727
v := e.longTable[i].offset
731
v = v - e.cur + e.maxMatchOff
733
e.longTable[i].offset = v
735
e.markAllShardsDirty()
736
e.cur = e.maxMatchOff
742
if len(src) < minNonLiteralBlockSize {
743
blk.extraLits = len(src)
744
blk.literals = blk.literals[:len(src)]
745
copy(blk.literals, src)
751
sLimit := int32(len(src)) - inputMargin
756
const kSearchStrength = 8
760
cv := load6432(src, s)
763
offset1 := int32(blk.recentOffsets[0])
764
offset2 := int32(blk.recentOffsets[1])
766
addLiterals := func(s *seq, until int32) {
767
if until == nextEmit {
770
blk.literals = append(blk.literals, src[nextEmit:until]...)
771
s.litLen = uint32(until - nextEmit)
774
println("recent offsets:", blk.recentOffsets)
781
canRepeat := len(blk.sequences) > 2
784
if debugAsserts && canRepeat && offset1 == 0 {
785
panic("offset0 was 0")
788
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
789
nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
790
candidateL := e.longTable[nextHashL]
791
candidateS := e.table[nextHashS]
794
repIndex := s - offset1 + repOff
795
entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
796
e.longTable[nextHashL] = entry
797
e.markLongShardDirty(nextHashL)
798
e.table[nextHashS] = entry
799
e.markShardDirty(nextHashS)
802
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
805
lenght := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
807
seq.matchLen = uint32(lenght - zstdMinMatch)
814
startLimit := nextEmit + 1
816
tMin := s - e.maxMatchOff
820
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
825
addLiterals(&seq, start)
830
println("repeat sequence", seq, "next s:", s)
832
blk.sequences = append(blk.sequences, seq)
837
println("repeat ended", s, lenght)
842
cv = load6432(src, s)
847
coffsetL := s - (candidateL.offset - e.cur)
848
coffsetS := s - (candidateS.offset - e.cur)
851
if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
855
t = candidateL.offset - e.cur
856
if debugAsserts && s <= t {
857
panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
859
if debugAsserts && s-t > e.maxMatchOff {
860
panic("s - t >e.maxMatchOff")
863
println("long match")
869
if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
873
cv := load6432(src, s+checkAt)
874
nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen)
875
candidateL = e.longTable[nextHashL]
876
coffsetL = s - (candidateL.offset - e.cur) + checkAt
879
e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)}
880
e.markLongShardDirty(nextHashL)
881
if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
885
t = candidateL.offset - e.cur
888
println("long match (after short)")
893
t = candidateS.offset - e.cur
894
if debugAsserts && s <= t {
895
panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
897
if debugAsserts && s-t > e.maxMatchOff {
898
panic("s - t >e.maxMatchOff")
900
if debugAsserts && t < 0 {
904
println("short match")
910
s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
914
cv = load6432(src, s)
922
if debugAsserts && s <= t {
923
panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
926
if debugAsserts && canRepeat && int(offset1) > len(src) {
927
panic("invalid offset")
931
l := e.matchlen(s+4, t+4, src) + 4
934
tMin := s - e.maxMatchOff
938
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
946
seq.litLen = uint32(s - nextEmit)
947
seq.matchLen = uint32(l - zstdMinMatch)
949
blk.literals = append(blk.literals, src[nextEmit:s]...)
951
seq.offset = uint32(s-t) + 3
954
println("sequence", seq, "next s:", s)
956
blk.sequences = append(blk.sequences, seq)
967
cv0 := load6432(src, index0)
968
cv1 := load6432(src, index1)
969
te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
970
te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
971
longHash1 := hashLen(cv0, dFastLongTableBits, dFastLongLen)
972
longHash2 := hashLen(cv0, dFastLongTableBits, dFastLongLen)
973
e.longTable[longHash1] = te0
974
e.longTable[longHash2] = te1
975
e.markLongShardDirty(longHash1)
976
e.markLongShardDirty(longHash2)
981
te0.val = uint32(cv0)
982
te1.val = uint32(cv1)
983
hashVal1 := hashLen(cv0, dFastShortTableBits, dFastShortLen)
984
hashVal2 := hashLen(cv1, dFastShortTableBits, dFastShortLen)
985
e.table[hashVal1] = te0
986
e.markShardDirty(hashVal1)
987
e.table[hashVal2] = te1
988
e.markShardDirty(hashVal2)
990
cv = load6432(src, s)
999
if load3232(src, o2) != uint32(cv) {
1005
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
1006
nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
1010
l := 4 + e.matchlen(s+4, o2+4, src)
1012
entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
1013
e.longTable[nextHashL] = entry
1014
e.markLongShardDirty(nextHashL)
1015
e.table[nextHashS] = entry
1016
e.markShardDirty(nextHashS)
1017
seq.matchLen = uint32(l) - zstdMinMatch
1025
println("sequence", seq, "next s:", s)
1027
blk.sequences = append(blk.sequences, seq)
1030
offset1, offset2 = offset2, offset1
1035
cv = load6432(src, s)
1039
if int(nextEmit) < len(src) {
1040
blk.literals = append(blk.literals, src[nextEmit:]...)
1041
blk.extraLits = len(src) - int(nextEmit)
1043
blk.recentOffsets[0] = uint32(offset1)
1044
blk.recentOffsets[1] = uint32(offset2)
1046
println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
1049
if len(src) > 64<<10 {
1050
e.markAllShardsDirty()
1055
func (e *doubleFastEncoder) Reset(d *dict, singleBlock bool) {
1056
e.fastEncoder.Reset(d, singleBlock)
1058
panic("doubleFastEncoder: Reset with dict not supported")
1063
func (e *doubleFastEncoderDict) Reset(d *dict, singleBlock bool) {
1064
allDirty := e.allDirty
1065
e.fastEncoderDict.Reset(d, singleBlock)
1071
if len(e.dictLongTable) != len(e.longTable) || d.id != e.lastDictID {
1072
if len(e.dictLongTable) != len(e.longTable) {
1073
e.dictLongTable = make([]tableEntry, len(e.longTable))
1075
if len(d.content) >= 8 {
1076
cv := load6432(d.content, 0)
1077
e.dictLongTable[hashLen(cv, dFastLongTableBits, dFastLongLen)] = tableEntry{
1079
offset: e.maxMatchOff,
1081
end := int32(len(d.content)) - 8 + e.maxMatchOff
1082
for i := e.maxMatchOff + 1; i < end; i++ {
1083
cv = cv>>8 | (uint64(d.content[i-e.maxMatchOff+7]) << 56)
1084
e.dictLongTable[hashLen(cv, dFastLongTableBits, dFastLongLen)] = tableEntry{
1094
e.cur = e.maxMatchOff
1098
for i := range e.longTableShardDirty {
1099
if e.longTableShardDirty[i] {
1105
if allDirty || dirtyShardCnt > dLongTableShardCnt/2 {
1106
copy(e.longTable[:], e.dictLongTable)
1107
for i := range e.longTableShardDirty {
1108
e.longTableShardDirty[i] = false
1112
for i := range e.longTableShardDirty {
1113
if !e.longTableShardDirty[i] {
1117
copy(e.longTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize], e.dictLongTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize])
1118
e.longTableShardDirty[i] = false
1122
func (e *doubleFastEncoderDict) markLongShardDirty(entryNum uint32) {
1123
e.longTableShardDirty[entryNum/dLongTableShardSize] = true