You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

fast_encoder.go 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // Copyright 2011 The Snappy-Go Authors. All rights reserved.
  2. // Modified for deflate by Klaus Post (c) 2015.
  3. // Use of this source code is governed by a BSD-style
  4. // license that can be found in the LICENSE file.
  5. package flate
  6. import (
  7. "fmt"
  8. "math/bits"
  9. )
  10. type fastEnc interface {
  11. Encode(dst *tokens, src []byte)
  12. Reset()
  13. }
  14. func newFastEnc(level int) fastEnc {
  15. switch level {
  16. case 1:
  17. return &fastEncL1{fastGen: fastGen{cur: maxStoreBlockSize}}
  18. case 2:
  19. return &fastEncL2{fastGen: fastGen{cur: maxStoreBlockSize}}
  20. case 3:
  21. return &fastEncL3{fastGen: fastGen{cur: maxStoreBlockSize}}
  22. case 4:
  23. return &fastEncL4{fastGen: fastGen{cur: maxStoreBlockSize}}
  24. case 5:
  25. return &fastEncL5{fastGen: fastGen{cur: maxStoreBlockSize}}
  26. case 6:
  27. return &fastEncL6{fastGen: fastGen{cur: maxStoreBlockSize}}
  28. default:
  29. panic("invalid level specified")
  30. }
  31. }
  32. const (
  33. tableBits = 15 // Bits used in the table
  34. tableSize = 1 << tableBits // Size of the table
  35. tableShift = 32 - tableBits // Right-shift to get the tableBits most significant bits of a uint32.
  36. baseMatchOffset = 1 // The smallest match offset
  37. baseMatchLength = 3 // The smallest match length per the RFC section 3.2.5
  38. maxMatchOffset = 1 << 15 // The largest match offset
  39. bTableBits = 17 // Bits used in the big tables
  40. bTableSize = 1 << bTableBits // Size of the table
  41. allocHistory = maxStoreBlockSize * 10 // Size to preallocate for history.
  42. bufferReset = (1 << 31) - allocHistory - maxStoreBlockSize - 1 // Reset the buffer offset when reaching this.
  43. )
  44. const (
  45. prime3bytes = 506832829
  46. prime4bytes = 2654435761
  47. prime5bytes = 889523592379
  48. prime6bytes = 227718039650203
  49. prime7bytes = 58295818150454627
  50. prime8bytes = 0xcf1bbcdcb7a56463
  51. )
  52. func load32(b []byte, i int) uint32 {
  53. // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
  54. b = b[i:]
  55. b = b[:4]
  56. return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
  57. }
  58. func load64(b []byte, i int) uint64 {
  59. // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
  60. b = b[i:]
  61. b = b[:8]
  62. return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
  63. uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
  64. }
  65. func load3232(b []byte, i int32) uint32 {
  66. // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
  67. b = b[i:]
  68. b = b[:4]
  69. return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
  70. }
  71. func load6432(b []byte, i int32) uint64 {
  72. // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
  73. b = b[i:]
  74. b = b[:8]
  75. return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
  76. uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
  77. }
  78. func hash(u uint32) uint32 {
  79. return (u * 0x1e35a7bd) >> tableShift
  80. }
  81. type tableEntry struct {
  82. offset int32
  83. }
  84. // fastGen maintains the table for matches,
  85. // and the previous byte block for level 2.
  86. // This is the generic implementation.
  87. type fastGen struct {
  88. hist []byte
  89. cur int32
  90. }
  91. func (e *fastGen) addBlock(src []byte) int32 {
  92. // check if we have space already
  93. if len(e.hist)+len(src) > cap(e.hist) {
  94. if cap(e.hist) == 0 {
  95. e.hist = make([]byte, 0, allocHistory)
  96. } else {
  97. if cap(e.hist) < maxMatchOffset*2 {
  98. panic("unexpected buffer size")
  99. }
  100. // Move down
  101. offset := int32(len(e.hist)) - maxMatchOffset
  102. copy(e.hist[0:maxMatchOffset], e.hist[offset:])
  103. e.cur += offset
  104. e.hist = e.hist[:maxMatchOffset]
  105. }
  106. }
  107. s := int32(len(e.hist))
  108. e.hist = append(e.hist, src...)
  109. return s
  110. }
  111. // hash4 returns the hash of u to fit in a hash table with h bits.
  112. // Preferably h should be a constant and should always be <32.
  113. func hash4u(u uint32, h uint8) uint32 {
  114. return (u * prime4bytes) >> ((32 - h) & 31)
  115. }
  116. type tableEntryPrev struct {
  117. Cur tableEntry
  118. Prev tableEntry
  119. }
  120. // hash4x64 returns the hash of the lowest 4 bytes of u to fit in a hash table with h bits.
  121. // Preferably h should be a constant and should always be <32.
  122. func hash4x64(u uint64, h uint8) uint32 {
  123. return (uint32(u) * prime4bytes) >> ((32 - h) & 31)
  124. }
  125. // hash7 returns the hash of the lowest 7 bytes of u to fit in a hash table with h bits.
  126. // Preferably h should be a constant and should always be <64.
  127. func hash7(u uint64, h uint8) uint32 {
  128. return uint32(((u << (64 - 56)) * prime7bytes) >> ((64 - h) & 63))
  129. }
  130. // hash8 returns the hash of u to fit in a hash table with h bits.
  131. // Preferably h should be a constant and should always be <64.
  132. func hash8(u uint64, h uint8) uint32 {
  133. return uint32((u * prime8bytes) >> ((64 - h) & 63))
  134. }
  135. // hash6 returns the hash of the lowest 6 bytes of u to fit in a hash table with h bits.
  136. // Preferably h should be a constant and should always be <64.
  137. func hash6(u uint64, h uint8) uint32 {
  138. return uint32(((u << (64 - 48)) * prime6bytes) >> ((64 - h) & 63))
  139. }
  140. // matchlen will return the match length between offsets and t in src.
  141. // The maximum length returned is maxMatchLength - 4.
  142. // It is assumed that s > t, that t >=0 and s < len(src).
  143. func (e *fastGen) matchlen(s, t int32, src []byte) int32 {
  144. if debugDecode {
  145. if t >= s {
  146. panic(fmt.Sprint("t >=s:", t, s))
  147. }
  148. if int(s) >= len(src) {
  149. panic(fmt.Sprint("s >= len(src):", s, len(src)))
  150. }
  151. if t < 0 {
  152. panic(fmt.Sprint("t < 0:", t))
  153. }
  154. if s-t > maxMatchOffset {
  155. panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
  156. }
  157. }
  158. s1 := int(s) + maxMatchLength - 4
  159. if s1 > len(src) {
  160. s1 = len(src)
  161. }
  162. // Extend the match to be as long as possible.
  163. return int32(matchLen(src[s:s1], src[t:]))
  164. }
  165. // matchlenLong will return the match length between offsets and t in src.
  166. // It is assumed that s > t, that t >=0 and s < len(src).
  167. func (e *fastGen) matchlenLong(s, t int32, src []byte) int32 {
  168. if debugDecode {
  169. if t >= s {
  170. panic(fmt.Sprint("t >=s:", t, s))
  171. }
  172. if int(s) >= len(src) {
  173. panic(fmt.Sprint("s >= len(src):", s, len(src)))
  174. }
  175. if t < 0 {
  176. panic(fmt.Sprint("t < 0:", t))
  177. }
  178. if s-t > maxMatchOffset {
  179. panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
  180. }
  181. }
  182. // Extend the match to be as long as possible.
  183. return int32(matchLen(src[s:], src[t:]))
  184. }
  185. // Reset the encoding table.
  186. func (e *fastGen) Reset() {
  187. if cap(e.hist) < allocHistory {
  188. e.hist = make([]byte, 0, allocHistory)
  189. }
  190. // We offset current position so everything will be out of reach.
  191. // If we are above the buffer reset it will be cleared anyway since len(hist) == 0.
  192. if e.cur <= bufferReset {
  193. e.cur += maxMatchOffset + int32(len(e.hist))
  194. }
  195. e.hist = e.hist[:0]
  196. }
  197. // matchLen returns the maximum length.
  198. // 'a' must be the shortest of the two.
  199. func matchLen(a, b []byte) int {
  200. b = b[:len(a)]
  201. var checked int
  202. if len(a) > 4 {
  203. // Try 4 bytes first
  204. if diff := load32(a, 0) ^ load32(b, 0); diff != 0 {
  205. return bits.TrailingZeros32(diff) >> 3
  206. }
  207. // Switch to 8 byte matching.
  208. checked = 4
  209. a = a[4:]
  210. b = b[4:]
  211. for len(a) >= 8 {
  212. b = b[:len(a)]
  213. if diff := load64(a, 0) ^ load64(b, 0); diff != 0 {
  214. return checked + (bits.TrailingZeros64(diff) >> 3)
  215. }
  216. checked += 8
  217. a = a[8:]
  218. b = b[8:]
  219. }
  220. }
  221. b = b[:len(a)]
  222. for i := range a {
  223. if a[i] != b[i] {
  224. return int(i) + checked
  225. }
  226. }
  227. return len(a) + checked
  228. }