您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

457 行
11 KiB

  1. // Copyright 2016 The Snappy-Go Authors. All rights reserved.
  2. // Copyright (c) 2019 Klaus Post. All rights reserved.
  3. // Use of this source code is governed by a BSD-style
  4. // license that can be found in the LICENSE file.
  5. package s2
  6. import (
  7. "bytes"
  8. "encoding/binary"
  9. "math/bits"
  10. )
  11. func load32(b []byte, i int) uint32 {
  12. return binary.LittleEndian.Uint32(b[i:])
  13. }
  14. func load64(b []byte, i int) uint64 {
  15. return binary.LittleEndian.Uint64(b[i:])
  16. }
  17. // hash6 returns the hash of the lowest 6 bytes of u to fit in a hash table with h bits.
  18. // Preferably h should be a constant and should always be <64.
  19. func hash6(u uint64, h uint8) uint32 {
  20. const prime6bytes = 227718039650203
  21. return uint32(((u << (64 - 48)) * prime6bytes) >> ((64 - h) & 63))
  22. }
  23. func encodeGo(dst, src []byte) []byte {
  24. if n := MaxEncodedLen(len(src)); n < 0 {
  25. panic(ErrTooLarge)
  26. } else if len(dst) < n {
  27. dst = make([]byte, n)
  28. }
  29. // The block starts with the varint-encoded length of the decompressed bytes.
  30. d := binary.PutUvarint(dst, uint64(len(src)))
  31. if len(src) == 0 {
  32. return dst[:d]
  33. }
  34. if len(src) < minNonLiteralBlockSize {
  35. d += emitLiteral(dst[d:], src)
  36. return dst[:d]
  37. }
  38. n := encodeBlockGo(dst[d:], src)
  39. if n > 0 {
  40. d += n
  41. return dst[:d]
  42. }
  43. // Not compressible
  44. d += emitLiteral(dst[d:], src)
  45. return dst[:d]
  46. }
  47. // encodeBlockGo encodes a non-empty src to a guaranteed-large-enough dst. It
  48. // assumes that the varint-encoded length of the decompressed bytes has already
  49. // been written.
  50. //
  51. // It also assumes that:
  52. // len(dst) >= MaxEncodedLen(len(src)) &&
  53. // minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
  54. func encodeBlockGo(dst, src []byte) (d int) {
  55. // Initialize the hash table.
  56. const (
  57. tableBits = 14
  58. maxTableSize = 1 << tableBits
  59. debug = false
  60. )
  61. var table [maxTableSize]uint32
  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 := len(src) - inputMargin
  66. // Bail if we can't compress to at least this.
  67. dstLimit := len(src) - len(src)>>5 - 5
  68. // nextEmit is where in src the next emitLiteral should start from.
  69. nextEmit := 0
  70. // The encoded form must start with a literal, as there are no previous
  71. // bytes to copy, so we start looking for hash matches at s == 1.
  72. s := 1
  73. cv := load64(src, s)
  74. // We search for a repeat at -1, but don't output repeats when nextEmit == 0
  75. repeat := 1
  76. for {
  77. candidate := 0
  78. for {
  79. // Next src position to check
  80. nextS := s + (s-nextEmit)>>6 + 4
  81. if nextS > sLimit {
  82. goto emitRemainder
  83. }
  84. hash0 := hash6(cv, tableBits)
  85. hash1 := hash6(cv>>8, tableBits)
  86. candidate = int(table[hash0])
  87. candidate2 := int(table[hash1])
  88. table[hash0] = uint32(s)
  89. table[hash1] = uint32(s + 1)
  90. hash2 := hash6(cv>>16, tableBits)
  91. // Check repeat at offset checkRep.
  92. const checkRep = 1
  93. if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
  94. base := s + checkRep
  95. // Extend back
  96. for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
  97. i--
  98. base--
  99. }
  100. d += emitLiteral(dst[d:], src[nextEmit:base])
  101. // Extend forward
  102. candidate := s - repeat + 4 + checkRep
  103. s += 4 + checkRep
  104. for s <= sLimit {
  105. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  106. s += bits.TrailingZeros64(diff) >> 3
  107. break
  108. }
  109. s += 8
  110. candidate += 8
  111. }
  112. if debug {
  113. // Validate match.
  114. if s <= candidate {
  115. panic("s <= candidate")
  116. }
  117. a := src[base:s]
  118. b := src[base-repeat : base-repeat+(s-base)]
  119. if !bytes.Equal(a, b) {
  120. panic("mismatch")
  121. }
  122. }
  123. if nextEmit > 0 {
  124. // same as `add := emitCopy(dst[d:], repeat, s-base)` but skips storing offset.
  125. d += emitRepeat(dst[d:], repeat, s-base)
  126. } else {
  127. // First match, cannot be repeat.
  128. d += emitCopy(dst[d:], repeat, s-base)
  129. }
  130. nextEmit = s
  131. if s >= sLimit {
  132. goto emitRemainder
  133. }
  134. cv = load64(src, s)
  135. continue
  136. }
  137. if uint32(cv) == load32(src, candidate) {
  138. break
  139. }
  140. candidate = int(table[hash2])
  141. if uint32(cv>>8) == load32(src, candidate2) {
  142. table[hash2] = uint32(s + 2)
  143. candidate = candidate2
  144. s++
  145. break
  146. }
  147. table[hash2] = uint32(s + 2)
  148. if uint32(cv>>16) == load32(src, candidate) {
  149. s += 2
  150. break
  151. }
  152. cv = load64(src, nextS)
  153. s = nextS
  154. }
  155. // Extend backwards.
  156. // The top bytes will be rechecked to get the full match.
  157. for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
  158. candidate--
  159. s--
  160. }
  161. // Bail if we exceed the maximum size.
  162. if d+(s-nextEmit) > dstLimit {
  163. return 0
  164. }
  165. // A 4-byte match has been found. We'll later see if more than 4 bytes
  166. // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
  167. // them as literal bytes.
  168. d += emitLiteral(dst[d:], src[nextEmit:s])
  169. // Call emitCopy, and then see if another emitCopy could be our next
  170. // move. Repeat until we find no match for the input immediately after
  171. // what was consumed by the last emitCopy call.
  172. //
  173. // If we exit this loop normally then we need to call emitLiteral next,
  174. // though we don't yet know how big the literal will be. We handle that
  175. // by proceeding to the next iteration of the main loop. We also can
  176. // exit this loop via goto if we get close to exhausting the input.
  177. for {
  178. // Invariant: we have a 4-byte match at s, and no need to emit any
  179. // literal bytes prior to s.
  180. base := s
  181. repeat = base - candidate
  182. // Extend the 4-byte match as long as possible.
  183. s += 4
  184. candidate += 4
  185. for s <= len(src)-8 {
  186. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  187. s += bits.TrailingZeros64(diff) >> 3
  188. break
  189. }
  190. s += 8
  191. candidate += 8
  192. }
  193. d += emitCopy(dst[d:], repeat, s-base)
  194. if debug {
  195. // Validate match.
  196. if s <= candidate {
  197. panic("s <= candidate")
  198. }
  199. a := src[base:s]
  200. b := src[base-repeat : base-repeat+(s-base)]
  201. if !bytes.Equal(a, b) {
  202. panic("mismatch")
  203. }
  204. }
  205. nextEmit = s
  206. if s >= sLimit {
  207. goto emitRemainder
  208. }
  209. if d > dstLimit {
  210. // Do we have space for more, if not bail.
  211. return 0
  212. }
  213. // Check for an immediate match, otherwise start search at s+1
  214. x := load64(src, s-2)
  215. m2Hash := hash6(x, tableBits)
  216. currHash := hash6(x>>16, tableBits)
  217. candidate = int(table[currHash])
  218. table[m2Hash] = uint32(s - 2)
  219. table[currHash] = uint32(s)
  220. if debug && s == candidate {
  221. panic("s == candidate")
  222. }
  223. if uint32(x>>16) != load32(src, candidate) {
  224. cv = load64(src, s+1)
  225. s++
  226. break
  227. }
  228. }
  229. }
  230. emitRemainder:
  231. if nextEmit < len(src) {
  232. // Bail if we exceed the maximum size.
  233. if d+len(src)-nextEmit > dstLimit {
  234. return 0
  235. }
  236. d += emitLiteral(dst[d:], src[nextEmit:])
  237. }
  238. return d
  239. }
  240. func encodeBlockSnappyGo(dst, src []byte) (d int) {
  241. // Initialize the hash table.
  242. const (
  243. tableBits = 14
  244. maxTableSize = 1 << tableBits
  245. )
  246. var table [maxTableSize]uint32
  247. // sLimit is when to stop looking for offset/length copies. The inputMargin
  248. // lets us use a fast path for emitLiteral in the main loop, while we are
  249. // looking for copies.
  250. sLimit := len(src) - inputMargin
  251. // Bail if we can't compress to at least this.
  252. dstLimit := len(src) - len(src)>>5 - 5
  253. // nextEmit is where in src the next emitLiteral should start from.
  254. nextEmit := 0
  255. // The encoded form must start with a literal, as there are no previous
  256. // bytes to copy, so we start looking for hash matches at s == 1.
  257. s := 1
  258. cv := load64(src, s)
  259. // We search for a repeat at -1, but don't output repeats when nextEmit == 0
  260. repeat := 1
  261. for {
  262. candidate := 0
  263. for {
  264. // Next src position to check
  265. nextS := s + (s-nextEmit)>>6 + 4
  266. if nextS > sLimit {
  267. goto emitRemainder
  268. }
  269. hash0 := hash6(cv, tableBits)
  270. hash1 := hash6(cv>>8, tableBits)
  271. candidate = int(table[hash0])
  272. candidate2 := int(table[hash1])
  273. table[hash0] = uint32(s)
  274. table[hash1] = uint32(s + 1)
  275. hash2 := hash6(cv>>16, tableBits)
  276. // Check repeat at offset checkRep.
  277. const checkRep = 1
  278. if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
  279. base := s + checkRep
  280. // Extend back
  281. for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
  282. i--
  283. base--
  284. }
  285. d += emitLiteral(dst[d:], src[nextEmit:base])
  286. // Extend forward
  287. candidate := s - repeat + 4 + checkRep
  288. s += 4 + checkRep
  289. for s <= sLimit {
  290. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  291. s += bits.TrailingZeros64(diff) >> 3
  292. break
  293. }
  294. s += 8
  295. candidate += 8
  296. }
  297. d += emitCopyNoRepeat(dst[d:], repeat, s-base)
  298. nextEmit = s
  299. if s >= sLimit {
  300. goto emitRemainder
  301. }
  302. cv = load64(src, s)
  303. continue
  304. }
  305. if uint32(cv) == load32(src, candidate) {
  306. break
  307. }
  308. candidate = int(table[hash2])
  309. if uint32(cv>>8) == load32(src, candidate2) {
  310. table[hash2] = uint32(s + 2)
  311. candidate = candidate2
  312. s++
  313. break
  314. }
  315. table[hash2] = uint32(s + 2)
  316. if uint32(cv>>16) == load32(src, candidate) {
  317. s += 2
  318. break
  319. }
  320. cv = load64(src, nextS)
  321. s = nextS
  322. }
  323. // Extend backwards
  324. for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
  325. candidate--
  326. s--
  327. }
  328. // Bail if we exceed the maximum size.
  329. if d+(s-nextEmit) > dstLimit {
  330. return 0
  331. }
  332. // A 4-byte match has been found. We'll later see if more than 4 bytes
  333. // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
  334. // them as literal bytes.
  335. d += emitLiteral(dst[d:], src[nextEmit:s])
  336. // Call emitCopy, and then see if another emitCopy could be our next
  337. // move. Repeat until we find no match for the input immediately after
  338. // what was consumed by the last emitCopy call.
  339. //
  340. // If we exit this loop normally then we need to call emitLiteral next,
  341. // though we don't yet know how big the literal will be. We handle that
  342. // by proceeding to the next iteration of the main loop. We also can
  343. // exit this loop via goto if we get close to exhausting the input.
  344. for {
  345. // Invariant: we have a 4-byte match at s, and no need to emit any
  346. // literal bytes prior to s.
  347. base := s
  348. repeat = base - candidate
  349. // Extend the 4-byte match as long as possible.
  350. s += 4
  351. candidate += 4
  352. for s <= len(src)-8 {
  353. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  354. s += bits.TrailingZeros64(diff) >> 3
  355. break
  356. }
  357. s += 8
  358. candidate += 8
  359. }
  360. d += emitCopyNoRepeat(dst[d:], repeat, s-base)
  361. if false {
  362. // Validate match.
  363. a := src[base:s]
  364. b := src[base-repeat : base-repeat+(s-base)]
  365. if !bytes.Equal(a, b) {
  366. panic("mismatch")
  367. }
  368. }
  369. nextEmit = s
  370. if s >= sLimit {
  371. goto emitRemainder
  372. }
  373. if d > dstLimit {
  374. // Do we have space for more, if not bail.
  375. return 0
  376. }
  377. // Check for an immediate match, otherwise start search at s+1
  378. x := load64(src, s-2)
  379. m2Hash := hash6(x, tableBits)
  380. currHash := hash6(x>>16, tableBits)
  381. candidate = int(table[currHash])
  382. table[m2Hash] = uint32(s - 2)
  383. table[currHash] = uint32(s)
  384. if uint32(x>>16) != load32(src, candidate) {
  385. cv = load64(src, s+1)
  386. s++
  387. break
  388. }
  389. }
  390. }
  391. emitRemainder:
  392. if nextEmit < len(src) {
  393. // Bail if we exceed the maximum size.
  394. if d+len(src)-nextEmit > dstLimit {
  395. return 0
  396. }
  397. d += emitLiteral(dst[d:], src[nextEmit:])
  398. }
  399. return d
  400. }