Skip to content

Commit 4703195

Browse files
authored
flate: Faster hashing for level 7-9 (#590)
Remove stateful hash and need for AND operation. Benchmarks show no change. Fixes #589
1 parent e77bf31 commit 4703195

File tree

2 files changed

+15
-23
lines changed

2 files changed

+15
-23
lines changed

flate/deflate.go

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -84,24 +84,23 @@ type advancedState struct {
8484
length int
8585
offset int
8686
maxInsertIndex int
87+
chainHead int
88+
hashOffset int
8789

88-
// Input hash chains
89-
// hashHead[hashValue] contains the largest inputIndex with the specified hash value
90-
// If hashHead[hashValue] is within the current window, then
91-
// hashPrev[hashHead[hashValue] & windowMask] contains the previous index
92-
// with the same hash value.
93-
chainHead int
94-
hashHead [hashSize]uint32
95-
hashPrev [windowSize]uint32
96-
hashOffset int
90+
ii uint16 // position of last match, intended to overflow to reset.
9791

9892
// input window: unprocessed data is window[index:windowEnd]
9993
index int
10094
estBitsPerByte int
10195
hashMatch [maxMatchLength + minMatchLength]uint32
10296

103-
hash uint32
104-
ii uint16 // position of last match, intended to overflow to reset.
97+
// Input hash chains
98+
// hashHead[hashValue] contains the largest inputIndex with the specified hash value
99+
// If hashHead[hashValue] is within the current window, then
100+
// hashPrev[hashHead[hashValue] & windowMask] contains the previous index
101+
// with the same hash value.
102+
hashHead [hashSize]uint32
103+
hashPrev [windowSize]uint32
105104
}
106105

107106
type compressor struct {
@@ -259,7 +258,6 @@ func (d *compressor) fillWindow(b []byte) {
259258
// Set the head of the hash chain to us.
260259
s.hashHead[newH] = uint32(di + s.hashOffset)
261260
}
262-
s.hash = newH
263261
}
264262
// Update window information.
265263
d.windowEnd += n
@@ -403,7 +401,6 @@ func (d *compressor) initDeflate() {
403401
s.hashOffset = 1
404402
s.length = minMatchLength - 1
405403
s.offset = 0
406-
s.hash = 0
407404
s.chainHead = -1
408405
}
409406

@@ -432,9 +429,6 @@ func (d *compressor) deflateLazy() {
432429
}
433430

434431
s.maxInsertIndex = d.windowEnd - (minMatchLength - 1)
435-
if s.index < s.maxInsertIndex {
436-
s.hash = hash4(d.window[s.index:])
437-
}
438432

439433
for {
440434
if sanity && s.index > d.windowEnd {
@@ -466,11 +460,11 @@ func (d *compressor) deflateLazy() {
466460
}
467461
if s.index < s.maxInsertIndex {
468462
// Update the hash
469-
s.hash = hash4(d.window[s.index:])
470-
ch := s.hashHead[s.hash&hashMask]
463+
hash := hash4(d.window[s.index:])
464+
ch := s.hashHead[hash]
471465
s.chainHead = int(ch)
472466
s.hashPrev[s.index&windowMask] = ch
473-
s.hashHead[s.hash&hashMask] = uint32(s.index + s.hashOffset)
467+
s.hashHead[hash] = uint32(s.index + s.hashOffset)
474468
}
475469
prevLength := s.length
476470
prevOffset := s.offset
@@ -503,7 +497,7 @@ func (d *compressor) deflateLazy() {
503497
end += prevIndex
504498
idx := prevIndex + prevLength - (4 - checkOff)
505499
h := hash4(d.window[idx:])
506-
ch2 := int(s.hashHead[h&hashMask]) - s.hashOffset - prevLength + (4 - checkOff)
500+
ch2 := int(s.hashHead[h]) - s.hashOffset - prevLength + (4 - checkOff)
507501
if ch2 > minIndex {
508502
length := matchLen(d.window[prevIndex:end], d.window[ch2:])
509503
// It seems like a pure length metric is best.
@@ -547,7 +541,6 @@ func (d *compressor) deflateLazy() {
547541
// Set the head of the hash chain to us.
548542
s.hashHead[newH] = uint32(di + s.hashOffset)
549543
}
550-
s.hash = newH
551544
}
552545

553546
s.index = newIndex
@@ -793,7 +786,6 @@ func (d *compressor) reset(w io.Writer) {
793786
d.tokens.Reset()
794787
s.length = minMatchLength - 1
795788
s.offset = 0
796-
s.hash = 0
797789
s.ii = 0
798790
s.maxInsertIndex = 0
799791
}

flate/fast_encoder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func (e *fastGen) addBlock(src []byte) int32 {
117117
// hash4 returns the hash of u to fit in a hash table with h bits.
118118
// Preferably h should be a constant and should always be <32.
119119
func hash4u(u uint32, h uint8) uint32 {
120-
return (u * prime4bytes) >> ((32 - h) & reg8SizeMask32)
120+
return (u * prime4bytes) >> (32 - h)
121121
}
122122

123123
type tableEntryPrev struct {

0 commit comments

Comments
 (0)