package matchfinder
import (
"encoding/binary"
"math"
)
type tableEntry struct {
val uint32
offset int32
}
const (
zfastTableBits = 15
zfastTableSize = 1 << zfastTableBits
zfastHashLen = 6
prime6Bytes = 227718039650203
)
type ZFast struct {
MaxDistance int
history []byte
current int32
table [zfastTableSize ]tableEntry
}
func (z *ZFast ) Reset () {
z .current = 0
z .table = [zfastTableSize ]tableEntry {}
z .history = z .history [:0 ]
}
func (z *ZFast ) FindMatches (dst []Match , src []byte ) []Match {
if z .MaxDistance == 0 {
z .MaxDistance = 1 << 16
}
if int (z .current ) >= int (math .MaxInt32 )-2 *z .MaxDistance -len (z .history ) {
minOffset := z .current + int32 (len (z .history )) - int32 (z .MaxDistance )
for i := range z .table {
v := z .table [i ].offset
if v < minOffset {
v = 0
} else {
v = v - z .current + int32 (z .MaxDistance )
}
z .table [i ].offset = v
}
z .current = int32 (z .MaxDistance )
}
if len (z .history )+len (src ) > cap (z .history ) {
if cap (z .history ) == 0 {
historySize := max (2 *z .MaxDistance , 1 <<20 , len (src ))
z .history = make ([]byte , 0 , historySize )
} else {
offset := len (z .history ) - z .MaxDistance
copy (z .history [:z .MaxDistance ], z .history [offset :])
z .current += int32 (offset )
z .history = z .history [:z .MaxDistance ]
}
}
s := int32 (len (z .history ))
z .history = append (z .history , src ...)
if len (src ) < 10 {
return append (dst , Match {
Unmatched : len (src ),
})
}
src = z .history
sLimit := int32 (len (src )) - 8
const stepSize = 2
nextEmit := s
cv := binary .LittleEndian .Uint64 (src [s :])
var offset1 , offset2 int32
mainLoop :
for {
var t int32
for {
nextHash := z .hash (cv )
nextHash2 := z .hash (cv >> 8 )
candidate := z .table [nextHash ]
candidate2 := z .table [nextHash2 ]
repIndex := s - offset1 + 2
z .table [nextHash ] = tableEntry {offset : s + z .current , val : uint32 (cv )}
z .table [nextHash2 ] = tableEntry {offset : s + z .current + 1 , val : uint32 (cv >> 8 )}
if offset1 != 0 && repIndex >= 0 && binary .LittleEndian .Uint32 (src [repIndex :]) == uint32 (cv >>16 ) {
end := extendMatch (src , int (repIndex +4 ), int (s +6 ))
start := s + 2
for repIndex > 0 && start > nextEmit && src [repIndex -1 ] == src [start -1 ] {
repIndex --
start --
}
dst = append (dst , Match {
Unmatched : int (start - nextEmit ),
Length : end - int (start ),
Distance : int (start - repIndex ),
})
s = int32 (end )
nextEmit = s
if s >= sLimit {
break mainLoop
}
cv = binary .LittleEndian .Uint64 (src [s :])
continue
}
coffset0 := s - (candidate .offset - z .current )
coffset1 := s - (candidate2 .offset - z .current ) + 1
if coffset0 < int32 (z .MaxDistance ) && uint32 (cv ) == candidate .val {
t = candidate .offset - z .current
if binary .LittleEndian .Uint32 (src [t :]) == uint32 (cv ) {
break
}
}
if coffset1 < int32 (z .MaxDistance ) && uint32 (cv >>8 ) == candidate2 .val {
t = candidate2 .offset - z .current
if binary .LittleEndian .Uint32 (src [t :]) == uint32 (cv >>8 ) {
s ++
break
}
}
s += stepSize + ((s - nextEmit ) >> 5 )
if s > sLimit {
break mainLoop
}
cv = binary .LittleEndian .Uint64 (src [s :])
}
offset2 = offset1
offset1 = s - t
end := extendMatch (src , int (t +4 ), int (s +4 ))
for t > 0 && s > nextEmit && src [t -1 ] == src [s -1 ] {
s --
t --
}
dst = append (dst , Match {
Unmatched : int (s - nextEmit ),
Length : end - int (s ),
Distance : int (s - t ),
})
s = int32 (end )
nextEmit = s
if s >= sLimit {
break mainLoop
}
cv = binary .LittleEndian .Uint64 (src [s :])
if o2 := s - offset2 ; offset2 != 0 && binary .LittleEndian .Uint32 (src [o2 :]) == uint32 (cv ) {
end := extendMatch (src , int (o2 +4 ), int (s +4 ))
nextHash := z .hash (cv )
z .table [nextHash ] = tableEntry {offset : s + z .current , val : uint32 (cv )}
dst = append (dst , Match {
Length : end - int (s ),
Distance : int (offset2 ),
})
s = int32 (end )
nextEmit = s
offset1 , offset2 = offset2 , offset1
if s >= sLimit {
break mainLoop
}
cv = binary .LittleEndian .Uint64 (src [s :])
}
}
if int (nextEmit ) < len (src ) {
dst = append (dst , Match {
Unmatched : len (src ) - int (nextEmit ),
})
}
return dst
}
func (z *ZFast ) hash (u uint64 ) uint32 {
return uint32 (((u << 16 ) * prime6Bytes ) >> (64 - zfastTableBits ))
}
The pages are generated with Golds v0.8.4 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .