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.
 
 
 
 

221 wiersze
5.3 KiB

  1. package flate
  2. import "fmt"
  3. type fastEncL4 struct {
  4. fastGen
  5. table [tableSize]tableEntry
  6. bTable [tableSize]tableEntry
  7. }
  8. func (e *fastEncL4) Encode(dst *tokens, src []byte) {
  9. const (
  10. inputMargin = 12 - 1
  11. minNonLiteralBlockSize = 1 + 1 + inputMargin
  12. )
  13. if debugDeflate && e.cur < 0 {
  14. panic(fmt.Sprint("e.cur < 0: ", e.cur))
  15. }
  16. // Protect against e.cur wraparound.
  17. for e.cur >= bufferReset {
  18. if len(e.hist) == 0 {
  19. for i := range e.table[:] {
  20. e.table[i] = tableEntry{}
  21. }
  22. for i := range e.bTable[:] {
  23. e.bTable[i] = tableEntry{}
  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].offset
  32. if v <= minOff {
  33. v = 0
  34. } else {
  35. v = v - e.cur + maxMatchOffset
  36. }
  37. e.table[i].offset = v
  38. }
  39. for i := range e.bTable[:] {
  40. v := e.bTable[i].offset
  41. if v <= minOff {
  42. v = 0
  43. } else {
  44. v = v - e.cur + maxMatchOffset
  45. }
  46. e.bTable[i].offset = v
  47. }
  48. e.cur = maxMatchOffset
  49. }
  50. s := e.addBlock(src)
  51. // This check isn't in the Snappy implementation, but there, the caller
  52. // instead of the callee handles this case.
  53. if len(src) < minNonLiteralBlockSize {
  54. // We do not fill the token table.
  55. // This will be picked up by caller.
  56. dst.n = uint16(len(src))
  57. return
  58. }
  59. // Override src
  60. src = e.hist
  61. nextEmit := s
  62. // sLimit is when to stop looking for offset/length copies. The inputMargin
  63. // lets us use a fast path for emitLiteral in the main loop, while we are
  64. // looking for copies.
  65. sLimit := int32(len(src) - inputMargin)
  66. // nextEmit is where in src the next emitLiteral should start from.
  67. cv := load6432(src, s)
  68. for {
  69. const skipLog = 6
  70. const doEvery = 1
  71. nextS := s
  72. var t int32
  73. for {
  74. nextHashS := hash4x64(cv, tableBits)
  75. nextHashL := hash7(cv, tableBits)
  76. s = nextS
  77. nextS = s + doEvery + (s-nextEmit)>>skipLog
  78. if nextS > sLimit {
  79. goto emitRemainder
  80. }
  81. // Fetch a short+long candidate
  82. sCandidate := e.table[nextHashS]
  83. lCandidate := e.bTable[nextHashL]
  84. next := load6432(src, nextS)
  85. entry := tableEntry{offset: s + e.cur}
  86. e.table[nextHashS] = entry
  87. e.bTable[nextHashL] = entry
  88. t = lCandidate.offset - e.cur
  89. if s-t < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.offset-e.cur) {
  90. // We got a long match. Use that.
  91. break
  92. }
  93. t = sCandidate.offset - e.cur
  94. if s-t < maxMatchOffset && uint32(cv) == load3232(src, sCandidate.offset-e.cur) {
  95. // Found a 4 match...
  96. lCandidate = e.bTable[hash7(next, tableBits)]
  97. // If the next long is a candidate, check if we should use that instead...
  98. lOff := nextS - (lCandidate.offset - e.cur)
  99. if lOff < maxMatchOffset && load3232(src, lCandidate.offset-e.cur) == uint32(next) {
  100. l1, l2 := matchLen(src[s+4:], src[t+4:]), matchLen(src[nextS+4:], src[nextS-lOff+4:])
  101. if l2 > l1 {
  102. s = nextS
  103. t = lCandidate.offset - e.cur
  104. }
  105. }
  106. break
  107. }
  108. cv = next
  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. // Extend the 4-byte match as long as possible.
  114. l := e.matchlenLong(s+4, t+4, src) + 4
  115. // Extend backwards
  116. for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
  117. s--
  118. t--
  119. l++
  120. }
  121. if nextEmit < s {
  122. if false {
  123. emitLiteral(dst, src[nextEmit:s])
  124. } else {
  125. for _, v := range src[nextEmit:s] {
  126. dst.tokens[dst.n] = token(v)
  127. dst.litHist[v]++
  128. dst.n++
  129. }
  130. }
  131. }
  132. if debugDeflate {
  133. if t >= s {
  134. panic("s-t")
  135. }
  136. if (s - t) > maxMatchOffset {
  137. panic(fmt.Sprintln("mmo", t))
  138. }
  139. if l < baseMatchLength {
  140. panic("bml")
  141. }
  142. }
  143. dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
  144. s += l
  145. nextEmit = s
  146. if nextS >= s {
  147. s = nextS + 1
  148. }
  149. if s >= sLimit {
  150. // Index first pair after match end.
  151. if int(s+8) < len(src) {
  152. cv := load6432(src, s)
  153. e.table[hash4x64(cv, tableBits)] = tableEntry{offset: s + e.cur}
  154. e.bTable[hash7(cv, tableBits)] = tableEntry{offset: s + e.cur}
  155. }
  156. goto emitRemainder
  157. }
  158. // Store every 3rd hash in-between
  159. if true {
  160. i := nextS
  161. if i < s-1 {
  162. cv := load6432(src, i)
  163. t := tableEntry{offset: i + e.cur}
  164. t2 := tableEntry{offset: t.offset + 1}
  165. e.bTable[hash7(cv, tableBits)] = t
  166. e.bTable[hash7(cv>>8, tableBits)] = t2
  167. e.table[hash4u(uint32(cv>>8), tableBits)] = t2
  168. i += 3
  169. for ; i < s-1; i += 3 {
  170. cv := load6432(src, i)
  171. t := tableEntry{offset: i + e.cur}
  172. t2 := tableEntry{offset: t.offset + 1}
  173. e.bTable[hash7(cv, tableBits)] = t
  174. e.bTable[hash7(cv>>8, tableBits)] = t2
  175. e.table[hash4u(uint32(cv>>8), tableBits)] = t2
  176. }
  177. }
  178. }
  179. // We could immediately start working at s now, but to improve
  180. // compression we first update the hash table at s-1 and at s.
  181. x := load6432(src, s-1)
  182. o := e.cur + s - 1
  183. prevHashS := hash4x64(x, tableBits)
  184. prevHashL := hash7(x, tableBits)
  185. e.table[prevHashS] = tableEntry{offset: o}
  186. e.bTable[prevHashL] = tableEntry{offset: o}
  187. cv = x >> 8
  188. }
  189. emitRemainder:
  190. if int(nextEmit) < len(src) {
  191. // If nothing was added, don't encode literals.
  192. if dst.n == 0 {
  193. return
  194. }
  195. emitLiteral(dst, src[nextEmit:])
  196. }
  197. }