1
2
3
4
5 package flate
6
7
8
9 type fastEncL5 struct {
10 fastGen
11 table [tableSize]tableEntry
12 bTable [tableSize]tableEntryPrev
13 }
14
15 func (e *fastEncL5) encode(dst *tokens, src []byte) {
16 const (
17 inputMargin = 12 - 1
18 minNonLiteralBlockSize = 1 + 1 + inputMargin
19 hashShortBytes = 4
20 )
21
22
23 for e.cur >= bufferReset {
24 if len(e.hist) == 0 {
25 clear(e.table[:])
26 clear(e.bTable[:])
27 e.cur = maxMatchOffset
28 break
29 }
30
31 minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
32 for i := range e.table[:] {
33 v := e.table[i].offset
34 if v <= minOff {
35 v = 0
36 } else {
37 v = v - e.cur + maxMatchOffset
38 }
39 e.table[i].offset = v
40 }
41 for i := range e.bTable[:] {
42 v := e.bTable[i]
43 if v.cur.offset <= minOff {
44 v.cur.offset = 0
45 v.prev.offset = 0
46 } else {
47 v.cur.offset = v.cur.offset - e.cur + maxMatchOffset
48 if v.prev.offset <= minOff {
49 v.prev.offset = 0
50 } else {
51 v.prev.offset = v.prev.offset - e.cur + maxMatchOffset
52 }
53 }
54 e.bTable[i] = v
55 }
56 e.cur = maxMatchOffset
57 }
58
59 s := e.addBlock(src)
60
61
62
63 if len(src) < minNonLiteralBlockSize {
64
65
66 dst.n = uint16(len(src))
67 return
68 }
69
70
71 src = e.hist
72
73
74 nextEmit := s
75
76
77
78
79 sLimit := int32(len(src) - inputMargin)
80
81 cv := loadLE64(src, s)
82 for {
83 const skipLog = 6
84 const doEvery = 1
85
86 nextS := s
87 var l int32
88 var t int32
89 for {
90 nextHashS := hashLen(cv, tableBits, hashShortBytes)
91 nextHashL := hashLen(cv, tableBits, hashLongBytes)
92
93 s = nextS
94 nextS = s + doEvery + (s-nextEmit)>>skipLog
95 if nextS > sLimit {
96 goto emitRemainder
97 }
98
99 sCandidate := e.table[nextHashS]
100 lCandidate := e.bTable[nextHashL]
101 next := loadLE64(src, nextS)
102 entry := tableEntry{offset: s + e.cur}
103 e.table[nextHashS] = entry
104 eLong := &e.bTable[nextHashL]
105 eLong.cur, eLong.prev = entry, eLong.cur
106
107 nextHashS = hashLen(next, tableBits, hashShortBytes)
108 nextHashL = hashLen(next, tableBits, hashLongBytes)
109
110 t = lCandidate.cur.offset - e.cur
111 if s-t < maxMatchOffset {
112 if uint32(cv) == loadLE32(src, t) {
113
114 e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
115 eLong := &e.bTable[nextHashL]
116 eLong.cur, eLong.prev = tableEntry{offset: nextS + e.cur}, eLong.cur
117
118 t2 := lCandidate.prev.offset - e.cur
119 if s-t2 < maxMatchOffset && uint32(cv) == loadLE32(src, t2) {
120 l = e.matchLenLimited(int(s+4), int(t+4), src) + 4
121 ml1 := e.matchLenLimited(int(s+4), int(t2+4), src) + 4
122 if ml1 > l {
123 t = t2
124 l = ml1
125 break
126 }
127 }
128 break
129 }
130 t = lCandidate.prev.offset - e.cur
131 if s-t < maxMatchOffset && uint32(cv) == loadLE32(src, t) {
132
133 e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
134 eLong := &e.bTable[nextHashL]
135 eLong.cur, eLong.prev = tableEntry{offset: nextS + e.cur}, eLong.cur
136 break
137 }
138 }
139
140 t = sCandidate.offset - e.cur
141 if s-t < maxMatchOffset && uint32(cv) == loadLE32(src, t) {
142
143 l = e.matchLenLimited(int(s+4), int(t+4), src) + 4
144 lCandidate = e.bTable[nextHashL]
145
146
147 e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
148 eLong := &e.bTable[nextHashL]
149 eLong.cur, eLong.prev = tableEntry{offset: nextS + e.cur}, eLong.cur
150
151
152 t2 := lCandidate.cur.offset - e.cur
153 if nextS-t2 < maxMatchOffset {
154 if loadLE32(src, t2) == uint32(next) {
155 ml := e.matchLenLimited(int(nextS+4), int(t2+4), src) + 4
156 if ml > l {
157 t = t2
158 s = nextS
159 l = ml
160 break
161 }
162 }
163
164 t2 = lCandidate.prev.offset - e.cur
165 if nextS-t2 < maxMatchOffset && loadLE32(src, t2) == uint32(next) {
166 ml := e.matchLenLimited(int(nextS+4), int(t2+4), src) + 4
167 if ml > l {
168 t = t2
169 s = nextS
170 l = ml
171 break
172 }
173 }
174 }
175 break
176 }
177 cv = next
178 }
179
180 if l == 0 {
181
182 l = e.matchLenLong(int(s+4), int(t+4), src) + 4
183 } else if l == maxMatchLength {
184 l += e.matchLenLong(int(s+l), int(t+l), src)
185 }
186
187
188 if sAt := s + l; l < 30 && sAt < sLimit {
189
190
191
192
193
194 const skipBeginning = 2
195 eLong := e.bTable[hashLen(loadLE64(src, sAt), tableBits, hashLongBytes)].cur.offset
196 t2 := eLong - e.cur - l + skipBeginning
197 s2 := s + skipBeginning
198 off := s2 - t2
199 if t2 >= 0 && off < maxMatchOffset && off > 0 {
200 if l2 := e.matchLenLong(int(s2), int(t2), src); l2 > l {
201 t = t2
202 l = l2
203 s = s2
204 }
205 }
206 }
207
208
209 for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
210 s--
211 t--
212 l++
213 }
214 if nextEmit < s {
215 for _, v := range src[nextEmit:s] {
216 dst.tokens[dst.n] = token(v)
217 dst.litHist[v]++
218 dst.n++
219 }
220 }
221
222 dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
223 s += l
224 nextEmit = s
225 if nextS >= s {
226 s = nextS + 1
227 }
228
229 if s >= sLimit {
230 goto emitRemainder
231 }
232
233
234 const hashEvery = 3
235 i := s - l + 1
236 if i < s-1 {
237 cv := loadLE64(src, i)
238 t := tableEntry{offset: i + e.cur}
239 e.table[hashLen(cv, tableBits, hashShortBytes)] = t
240 eLong := &e.bTable[hashLen(cv, tableBits, hashLongBytes)]
241 eLong.cur, eLong.prev = t, eLong.cur
242
243
244 cv >>= 8
245 t = tableEntry{offset: t.offset + 1}
246 eLong = &e.bTable[hashLen(cv, tableBits, hashLongBytes)]
247 eLong.cur, eLong.prev = t, eLong.cur
248
249
250 cv >>= 8
251 t = tableEntry{offset: t.offset + 1}
252 e.table[hashLen(cv, tableBits, hashShortBytes)] = t
253
254
255 i += 4
256 for ; i < s-1; i += hashEvery {
257 cv := loadLE64(src, i)
258 t := tableEntry{offset: i + e.cur}
259 t2 := tableEntry{offset: t.offset + 1}
260 eLong := &e.bTable[hashLen(cv, tableBits, hashLongBytes)]
261 eLong.cur, eLong.prev = t, eLong.cur
262 e.table[hashLen(cv>>8, tableBits, hashShortBytes)] = t2
263 }
264 }
265
266
267
268 x := loadLE64(src, s-1)
269 o := e.cur + s - 1
270 prevHashS := hashLen(x, tableBits, hashShortBytes)
271 prevHashL := hashLen(x, tableBits, hashLongBytes)
272 e.table[prevHashS] = tableEntry{offset: o}
273 eLong := &e.bTable[prevHashL]
274 eLong.cur, eLong.prev = tableEntry{offset: o}, eLong.cur
275 cv = x >> 8
276 }
277
278 emitRemainder:
279 if int(nextEmit) < len(src) {
280
281 if dst.n == 0 {
282 return
283 }
284
285 emitLiterals(dst, src[nextEmit:])
286 }
287 }
288
View as plain text