source: code/trunk/vendor/github.com/klauspost/compress/flate/level3.go@ 145

Last change on this file since 145 was 145, checked in by Izuru Yakumo, 22 months ago

Updated the Makefile and vendored depedencies

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 6.1 KB
Line 
1package flate
2
3import "fmt"
4
5// fastEncL3
6type fastEncL3 struct {
7 fastGen
8 table [1 << 16]tableEntryPrev
9}
10
11// Encode uses a similar algorithm to level 2, will check up to two candidates.
12func (e *fastEncL3) Encode(dst *tokens, src []byte) {
13 const (
14 inputMargin = 8 - 1
15 minNonLiteralBlockSize = 1 + 1 + inputMargin
16 tableBits = 16
17 tableSize = 1 << tableBits
18 )
19
20 if debugDeflate && e.cur < 0 {
21 panic(fmt.Sprint("e.cur < 0: ", e.cur))
22 }
23
24 // Protect against e.cur wraparound.
25 for e.cur >= bufferReset {
26 if len(e.hist) == 0 {
27 for i := range e.table[:] {
28 e.table[i] = tableEntryPrev{}
29 }
30 e.cur = maxMatchOffset
31 break
32 }
33 // Shift down everything in the table that isn't already too far away.
34 minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
35 for i := range e.table[:] {
36 v := e.table[i]
37 if v.Cur.offset <= minOff {
38 v.Cur.offset = 0
39 } else {
40 v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset
41 }
42 if v.Prev.offset <= minOff {
43 v.Prev.offset = 0
44 } else {
45 v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset
46 }
47 e.table[i] = v
48 }
49 e.cur = maxMatchOffset
50 }
51
52 s := e.addBlock(src)
53
54 // Skip if too small.
55 if len(src) < minNonLiteralBlockSize {
56 // We do not fill the token table.
57 // This will be picked up by caller.
58 dst.n = uint16(len(src))
59 return
60 }
61
62 // Override src
63 src = e.hist
64 nextEmit := s
65
66 // sLimit is when to stop looking for offset/length copies. The inputMargin
67 // lets us use a fast path for emitLiteral in the main loop, while we are
68 // looking for copies.
69 sLimit := int32(len(src) - inputMargin)
70
71 // nextEmit is where in src the next emitLiteral should start from.
72 cv := load3232(src, s)
73 for {
74 const skipLog = 6
75 nextS := s
76 var candidate tableEntry
77 for {
78 nextHash := hash4u(cv, tableBits)
79 s = nextS
80 nextS = s + 1 + (s-nextEmit)>>skipLog
81 if nextS > sLimit {
82 goto emitRemainder
83 }
84 candidates := e.table[nextHash]
85 now := load3232(src, nextS)
86
87 // Safe offset distance until s + 4...
88 minOffset := e.cur + s - (maxMatchOffset - 4)
89 e.table[nextHash] = tableEntryPrev{Prev: candidates.Cur, Cur: tableEntry{offset: s + e.cur}}
90
91 // Check both candidates
92 candidate = candidates.Cur
93 if candidate.offset < minOffset {
94 cv = now
95 // Previous will also be invalid, we have nothing.
96 continue
97 }
98
99 if cv == load3232(src, candidate.offset-e.cur) {
100 if candidates.Prev.offset < minOffset || cv != load3232(src, candidates.Prev.offset-e.cur) {
101 break
102 }
103 // Both match and are valid, pick longest.
104 offset := s - (candidate.offset - e.cur)
105 o2 := s - (candidates.Prev.offset - e.cur)
106 l1, l2 := matchLen(src[s+4:], src[s-offset+4:]), matchLen(src[s+4:], src[s-o2+4:])
107 if l2 > l1 {
108 candidate = candidates.Prev
109 }
110 break
111 } else {
112 // We only check if value mismatches.
113 // Offset will always be invalid in other cases.
114 candidate = candidates.Prev
115 if candidate.offset > minOffset && cv == load3232(src, candidate.offset-e.cur) {
116 break
117 }
118 }
119 cv = now
120 }
121
122 // Call emitCopy, and then see if another emitCopy could be our next
123 // move. Repeat until we find no match for the input immediately after
124 // what was consumed by the last emitCopy call.
125 //
126 // If we exit this loop normally then we need to call emitLiteral next,
127 // though we don't yet know how big the literal will be. We handle that
128 // by proceeding to the next iteration of the main loop. We also can
129 // exit this loop via goto if we get close to exhausting the input.
130 for {
131 // Invariant: we have a 4-byte match at s, and no need to emit any
132 // literal bytes prior to s.
133
134 // Extend the 4-byte match as long as possible.
135 //
136 t := candidate.offset - e.cur
137 l := e.matchlenLong(s+4, t+4, src) + 4
138
139 // Extend backwards
140 for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
141 s--
142 t--
143 l++
144 }
145 if nextEmit < s {
146 if false {
147 emitLiteral(dst, src[nextEmit:s])
148 } else {
149 for _, v := range src[nextEmit:s] {
150 dst.tokens[dst.n] = token(v)
151 dst.litHist[v]++
152 dst.n++
153 }
154 }
155 }
156
157 dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
158 s += l
159 nextEmit = s
160 if nextS >= s {
161 s = nextS + 1
162 }
163
164 if s >= sLimit {
165 t += l
166 // Index first pair after match end.
167 if int(t+4) < len(src) && t > 0 {
168 cv := load3232(src, t)
169 nextHash := hash4u(cv, tableBits)
170 e.table[nextHash] = tableEntryPrev{
171 Prev: e.table[nextHash].Cur,
172 Cur: tableEntry{offset: e.cur + t},
173 }
174 }
175 goto emitRemainder
176 }
177
178 // Store every 5th hash in-between.
179 for i := s - l + 2; i < s-5; i += 5 {
180 nextHash := hash4u(load3232(src, i), tableBits)
181 e.table[nextHash] = tableEntryPrev{
182 Prev: e.table[nextHash].Cur,
183 Cur: tableEntry{offset: e.cur + i}}
184 }
185 // We could immediately start working at s now, but to improve
186 // compression we first update the hash table at s-2 to s.
187 x := load6432(src, s-2)
188 prevHash := hash4u(uint32(x), tableBits)
189
190 e.table[prevHash] = tableEntryPrev{
191 Prev: e.table[prevHash].Cur,
192 Cur: tableEntry{offset: e.cur + s - 2},
193 }
194 x >>= 8
195 prevHash = hash4u(uint32(x), tableBits)
196
197 e.table[prevHash] = tableEntryPrev{
198 Prev: e.table[prevHash].Cur,
199 Cur: tableEntry{offset: e.cur + s - 1},
200 }
201 x >>= 8
202 currHash := hash4u(uint32(x), tableBits)
203 candidates := e.table[currHash]
204 cv = uint32(x)
205 e.table[currHash] = tableEntryPrev{
206 Prev: candidates.Cur,
207 Cur: tableEntry{offset: s + e.cur},
208 }
209
210 // Check both candidates
211 candidate = candidates.Cur
212 minOffset := e.cur + s - (maxMatchOffset - 4)
213
214 if candidate.offset > minOffset {
215 if cv == load3232(src, candidate.offset-e.cur) {
216 // Found a match...
217 continue
218 }
219 candidate = candidates.Prev
220 if candidate.offset > minOffset && cv == load3232(src, candidate.offset-e.cur) {
221 // Match at prev...
222 continue
223 }
224 }
225 cv = uint32(x >> 8)
226 s++
227 break
228 }
229 }
230
231emitRemainder:
232 if int(nextEmit) < len(src) {
233 // If nothing was added, don't encode literals.
234 if dst.n == 0 {
235 return
236 }
237
238 emitLiteral(dst, src[nextEmit:])
239 }
240}
Note: See TracBrowser for help on using the repository browser.