1
2
3
4
5 package flate
6
7 const (
8 l3TableBits = 16
9 l3TableSize = 1 << l3TableBits
10 )
11
12
13
14
15 type fastEncL3 struct {
16 fastGen
17 table [l3TableSize]tableEntryPrev
18 }
19
20 func (e *fastEncL3) encode(dst *tokens, src []byte) {
21 const (
22 inputMargin = 12 - 1
23 minNonLiteralBlockSize = 1 + 1 + inputMargin
24 hashBytes = 5
25 )
26
27
28 for e.cur >= bufferReset {
29 if len(e.hist) == 0 {
30 clear(e.table[:])
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 := loadLE64(src, s)
74 for {
75 const skipLog = 7
76 nextS := s
77 var candidate tableEntry
78 for {
79 nextHash := hashLen(cv, l3TableBits, 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 := loadLE64(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) == loadLE32(src, candidate.offset-e.cur) {
101 if candidates.prev.offset < minOffset || uint32(cv) != loadLE32(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) == loadLE32(src, candidate.offset-e.cur) {
117 break
118 }
119 }
120 cv = now
121 }
122
123 for {
124
125
126 t := candidate.offset - e.cur
127 l := e.matchLenLong(int(s+4), int(t+4), src) + 4
128
129
130 for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
131 s--
132 t--
133 l++
134 }
135
136 if nextEmit < s {
137 for _, v := range src[nextEmit:s] {
138 dst.tokens[dst.n] = token(v)
139 dst.litHist[v]++
140 dst.n++
141 }
142 }
143
144
145 dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
146 s += l
147 nextEmit = s
148 if nextS >= s {
149 s = nextS + 1
150 }
151
152 if s >= sLimit {
153 t += l
154
155 if int(t+8) < len(src) && t > 0 {
156 cv = loadLE64(src, t)
157 nextHash := hashLen(cv, l3TableBits, hashBytes)
158 e.table[nextHash] = tableEntryPrev{
159 prev: e.table[nextHash].cur,
160 cur: tableEntry{offset: e.cur + t},
161 }
162 }
163 goto emitRemainder
164 }
165
166
167 for i := s - l + 2; i < s-5; i += 6 {
168 nextHash := hashLen(loadLE64(src, i), l3TableBits, hashBytes)
169 e.table[nextHash] = tableEntryPrev{
170 prev: e.table[nextHash].cur,
171 cur: tableEntry{offset: e.cur + i}}
172 }
173
174
175 x := loadLE64(src, s-2)
176 prevHash := hashLen(x, l3TableBits, hashBytes)
177
178 e.table[prevHash] = tableEntryPrev{
179 prev: e.table[prevHash].cur,
180 cur: tableEntry{offset: e.cur + s - 2},
181 }
182 x >>= 8
183 prevHash = hashLen(x, l3TableBits, hashBytes)
184
185 e.table[prevHash] = tableEntryPrev{
186 prev: e.table[prevHash].cur,
187 cur: tableEntry{offset: e.cur + s - 1},
188 }
189 x >>= 8
190 currHash := hashLen(x, l3TableBits, hashBytes)
191 candidates := e.table[currHash]
192 cv = x
193 e.table[currHash] = tableEntryPrev{
194 prev: candidates.cur,
195 cur: tableEntry{offset: s + e.cur},
196 }
197
198
199 candidate = candidates.cur
200 minOffset := e.cur + s - (maxMatchOffset - 4)
201
202 if candidate.offset > minOffset {
203 if uint32(cv) == loadLE32(src, candidate.offset-e.cur) {
204
205 continue
206 }
207 candidate = candidates.prev
208 if candidate.offset > minOffset && uint32(cv) == loadLE32(src, candidate.offset-e.cur) {
209
210 continue
211 }
212 }
213 cv = x >> 8
214 s++
215 break
216 }
217 }
218
219 emitRemainder:
220 if int(nextEmit) < len(src) {
221
222 if dst.n == 0 {
223 return
224 }
225
226 emitLiterals(dst, src[nextEmit:])
227 }
228 }
229
View as plain text