source: code/trunk/vendor/github.com/klauspost/compress/flate/level2.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: 5.8 KB
Line 
1package flate
2
3import "fmt"
4
5// fastGen maintains the table for matches,
6// and the previous byte block for level 2.
7// This is the generic implementation.
8type fastEncL2 struct {
9 fastGen
10 table [bTableSize]tableEntry
11}
12
13// EncodeL2 uses a similar algorithm to level 1, but is capable
14// of matching across blocks giving better compression at a small slowdown.
15func (e *fastEncL2) Encode(dst *tokens, src []byte) {
16 const (
17 inputMargin = 12 - 1
18 minNonLiteralBlockSize = 1 + 1 + inputMargin
19 )
20
21 if debugDeflate && e.cur < 0 {
22 panic(fmt.Sprint("e.cur < 0: ", e.cur))
23 }
24
25 // Protect against e.cur wraparound.
26 for e.cur >= bufferReset {
27 if len(e.hist) == 0 {
28 for i := range e.table[:] {
29 e.table[i] = tableEntry{}
30 }
31 e.cur = maxMatchOffset
32 break
33 }
34 // Shift down everything in the table that isn't already too far away.
35 minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
36 for i := range e.table[:] {
37 v := e.table[i].offset
38 if v <= minOff {
39 v = 0
40 } else {
41 v = v - e.cur + maxMatchOffset
42 }
43 e.table[i].offset = v
44 }
45 e.cur = maxMatchOffset
46 }
47
48 s := e.addBlock(src)
49
50 // This check isn't in the Snappy implementation, but there, the caller
51 // instead of the callee handles this case.
52 if len(src) < minNonLiteralBlockSize {
53 // We do not fill the token table.
54 // This will be picked up by caller.
55 dst.n = uint16(len(src))
56 return
57 }
58
59 // Override src
60 src = e.hist
61 nextEmit := s
62
63 // sLimit is when to stop looking for offset/length copies. The inputMargin
64 // lets us use a fast path for emitLiteral in the main loop, while we are
65 // looking for copies.
66 sLimit := int32(len(src) - inputMargin)
67
68 // nextEmit is where in src the next emitLiteral should start from.
69 cv := load3232(src, s)
70 for {
71 // When should we start skipping if we haven't found matches in a long while.
72 const skipLog = 5
73 const doEvery = 2
74
75 nextS := s
76 var candidate tableEntry
77 for {
78 nextHash := hash4u(cv, bTableBits)
79 s = nextS
80 nextS = s + doEvery + (s-nextEmit)>>skipLog
81 if nextS > sLimit {
82 goto emitRemainder
83 }
84 candidate = e.table[nextHash]
85 now := load6432(src, nextS)
86 e.table[nextHash] = tableEntry{offset: s + e.cur}
87 nextHash = hash4u(uint32(now), bTableBits)
88
89 offset := s - (candidate.offset - e.cur)
90 if offset < maxMatchOffset && cv == load3232(src, candidate.offset-e.cur) {
91 e.table[nextHash] = tableEntry{offset: nextS + e.cur}
92 break
93 }
94
95 // Do one right away...
96 cv = uint32(now)
97 s = nextS
98 nextS++
99 candidate = e.table[nextHash]
100 now >>= 8
101 e.table[nextHash] = tableEntry{offset: s + e.cur}
102
103 offset = s - (candidate.offset - e.cur)
104 if offset < maxMatchOffset && cv == load3232(src, candidate.offset-e.cur) {
105 break
106 }
107 cv = uint32(now)
108 }
109
110 // A 4-byte match has been found. We'll later see if more than 4 bytes
111 // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
112 // them as literal bytes.
113
114 // Call emitCopy, and then see if another emitCopy could be our next
115 // move. Repeat until we find no match for the input immediately after
116 // what was consumed by the last emitCopy call.
117 //
118 // If we exit this loop normally then we need to call emitLiteral next,
119 // though we don't yet know how big the literal will be. We handle that
120 // by proceeding to the next iteration of the main loop. We also can
121 // exit this loop via goto if we get close to exhausting the input.
122 for {
123 // Invariant: we have a 4-byte match at s, and no need to emit any
124 // literal bytes prior to s.
125
126 // Extend the 4-byte match as long as possible.
127 t := candidate.offset - e.cur
128 l := e.matchlenLong(s+4, t+4, src) + 4
129
130 // Extend backwards
131 for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
132 s--
133 t--
134 l++
135 }
136 if nextEmit < s {
137 if false {
138 emitLiteral(dst, src[nextEmit:s])
139 } else {
140 for _, v := range src[nextEmit:s] {
141 dst.tokens[dst.n] = token(v)
142 dst.litHist[v]++
143 dst.n++
144 }
145 }
146 }
147
148 dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
149 s += l
150 nextEmit = s
151 if nextS >= s {
152 s = nextS + 1
153 }
154
155 if s >= sLimit {
156 // Index first pair after match end.
157 if int(s+l+4) < len(src) {
158 cv := load3232(src, s)
159 e.table[hash4u(cv, bTableBits)] = tableEntry{offset: s + e.cur}
160 }
161 goto emitRemainder
162 }
163
164 // Store every second hash in-between, but offset by 1.
165 for i := s - l + 2; i < s-5; i += 7 {
166 x := load6432(src, i)
167 nextHash := hash4u(uint32(x), bTableBits)
168 e.table[nextHash] = tableEntry{offset: e.cur + i}
169 // Skip one
170 x >>= 16
171 nextHash = hash4u(uint32(x), bTableBits)
172 e.table[nextHash] = tableEntry{offset: e.cur + i + 2}
173 // Skip one
174 x >>= 16
175 nextHash = hash4u(uint32(x), bTableBits)
176 e.table[nextHash] = tableEntry{offset: e.cur + i + 4}
177 }
178
179 // We could immediately start working at s now, but to improve
180 // compression we first update the hash table at s-2 to s. If
181 // another emitCopy is not our next move, also calculate nextHash
182 // at s+1. At least on GOARCH=amd64, these three hash calculations
183 // are faster as one load64 call (with some shifts) instead of
184 // three load32 calls.
185 x := load6432(src, s-2)
186 o := e.cur + s - 2
187 prevHash := hash4u(uint32(x), bTableBits)
188 prevHash2 := hash4u(uint32(x>>8), bTableBits)
189 e.table[prevHash] = tableEntry{offset: o}
190 e.table[prevHash2] = tableEntry{offset: o + 1}
191 currHash := hash4u(uint32(x>>16), bTableBits)
192 candidate = e.table[currHash]
193 e.table[currHash] = tableEntry{offset: o + 2}
194
195 offset := s - (candidate.offset - e.cur)
196 if offset > maxMatchOffset || uint32(x>>16) != load3232(src, candidate.offset-e.cur) {
197 cv = uint32(x >> 24)
198 s++
199 break
200 }
201 }
202 }
203
204emitRemainder:
205 if int(nextEmit) < len(src) {
206 // If nothing was added, don't encode literals.
207 if dst.n == 0 {
208 return
209 }
210
211 emitLiteral(dst, src[nextEmit:])
212 }
213}
Note: See TracBrowser for help on using the repository browser.