...
1 package flate
2
3 import "fmt"
4
5
6 type fastEncL3 struct {
7 fastGen
8 table [1 << 16]tableEntryPrev
9 }
10
11
12 func (e *fastEncL3) Encode(dst *tokens, src []byte) {
13 const (
14 inputMargin = 12 - 1
15 minNonLiteralBlockSize = 1 + 1 + inputMargin
16 tableBits = 16
17 tableSize = 1 << tableBits
18 hashBytes = 5
19 )
20
21 if debugDeflate && e.cur < 0 {
22 panic(fmt.Sprint("e.cur < 0: ", e.cur))
23 }
24
25
26 for e.cur >= bufferReset {
27 if len(e.hist) == 0 {
28 for i := range e.table[:] {
29 e.table[i] = tableEntryPrev{}
30 }
31 e.cur = maxMatchOffset
32 break
33 }
34
35 minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
36 for i := range e.table[:] {
37 v := e.table[i]
38 if v.Cur.offset <= minOff {
39 v.Cur.offset = 0
40 } else {
41 v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset
42 }
43 if v.Prev.offset <= minOff {
44 v.Prev.offset = 0
45 } else {
46 v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset
47 }
48 e.table[i] = v
49 }
50 e.cur = maxMatchOffset
51 }
52
53 s := e.addBlock(src)
54
55
56 if len(src) < minNonLiteralBlockSize {
57
58
59 dst.n = uint16(len(src))
60 return
61 }
62
63
64 src = e.hist
65 nextEmit := s
66
67
68
69
70 sLimit := int32(len(src) - inputMargin)
71
72
73 cv := load6432(src, s)
74 for {
75 const skipLog = 7
76 nextS := s
77 var candidate tableEntry
78 for {
79 nextHash := hashLen(cv, tableBits, hashBytes)
80 s = nextS
81 nextS = s + 1 + (s-nextEmit)>>skipLog
82 if nextS > sLimit {
83 goto emitRemainder
84 }
85 candidates := e.table[nextHash]
86 now := load6432(src, nextS)
87
88
89 minOffset := e.cur + s - (maxMatchOffset - 4)
90 e.table[nextHash] = tableEntryPrev{Prev: candidates.Cur, Cur: tableEntry{offset: s + e.cur}}
91
92
93 candidate = candidates.Cur
94 if candidate.offset < minOffset {
95 cv = now
96
97 continue
98 }
99
100 if uint32(cv) == load3232(src, candidate.offset-e.cur) {
101 if candidates.Prev.offset < minOffset || uint32(cv) != load3232(src, candidates.Prev.offset-e.cur) {
102 break
103 }
104
105 offset := s - (candidate.offset - e.cur)
106 o2 := s - (candidates.Prev.offset - e.cur)
107 l1, l2 := matchLen(src[s+4:], src[s-offset+4:]), matchLen(src[s+4:], src[s-o2+4:])
108 if l2 > l1 {
109 candidate = candidates.Prev
110 }
111 break
112 } else {
113
114
115 candidate = candidates.Prev
116 if candidate.offset > minOffset && uint32(cv) == load3232(src, candidate.offset-e.cur) {
117 break
118 }
119 }
120 cv = now
121 }
122
123
124
125
126
127
128
129
130
131 for {
132
133
134
135
136
137 t := candidate.offset - e.cur
138 l := e.matchlenLong(s+4, t+4, src) + 4
139
140
141 for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
142 s--
143 t--
144 l++
145 }
146 if nextEmit < s {
147 if false {
148 emitLiteral(dst, src[nextEmit:s])
149 } else {
150 for _, v := range src[nextEmit:s] {
151 dst.tokens[dst.n] = token(v)
152 dst.litHist[v]++
153 dst.n++
154 }
155 }
156 }
157
158 dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
159 s += l
160 nextEmit = s
161 if nextS >= s {
162 s = nextS + 1
163 }
164
165 if s >= sLimit {
166 t += l
167
168 if int(t+8) < len(src) && t > 0 {
169 cv = load6432(src, t)
170 nextHash := hashLen(cv, tableBits, hashBytes)
171 e.table[nextHash] = tableEntryPrev{
172 Prev: e.table[nextHash].Cur,
173 Cur: tableEntry{offset: e.cur + t},
174 }
175 }
176 goto emitRemainder
177 }
178
179
180 for i := s - l + 2; i < s-5; i += 6 {
181 nextHash := hashLen(load6432(src, i), tableBits, hashBytes)
182 e.table[nextHash] = tableEntryPrev{
183 Prev: e.table[nextHash].Cur,
184 Cur: tableEntry{offset: e.cur + i}}
185 }
186
187
188 x := load6432(src, s-2)
189 prevHash := hashLen(x, tableBits, hashBytes)
190
191 e.table[prevHash] = tableEntryPrev{
192 Prev: e.table[prevHash].Cur,
193 Cur: tableEntry{offset: e.cur + s - 2},
194 }
195 x >>= 8
196 prevHash = hashLen(x, tableBits, hashBytes)
197
198 e.table[prevHash] = tableEntryPrev{
199 Prev: e.table[prevHash].Cur,
200 Cur: tableEntry{offset: e.cur + s - 1},
201 }
202 x >>= 8
203 currHash := hashLen(x, tableBits, hashBytes)
204 candidates := e.table[currHash]
205 cv = x
206 e.table[currHash] = tableEntryPrev{
207 Prev: candidates.Cur,
208 Cur: tableEntry{offset: s + e.cur},
209 }
210
211
212 candidate = candidates.Cur
213 minOffset := e.cur + s - (maxMatchOffset - 4)
214
215 if candidate.offset > minOffset {
216 if uint32(cv) == load3232(src, candidate.offset-e.cur) {
217
218 continue
219 }
220 candidate = candidates.Prev
221 if candidate.offset > minOffset && uint32(cv) == load3232(src, candidate.offset-e.cur) {
222
223 continue
224 }
225 }
226 cv = x >> 8
227 s++
228 break
229 }
230 }
231
232 emitRemainder:
233 if int(nextEmit) < len(src) {
234
235 if dst.n == 0 {
236 return
237 }
238
239 emitLiteral(dst, src[nextEmit:])
240 }
241 }
242
View as plain text