Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

241 wiersze
6.1 KiB

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