encode_all.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. b = b[i:]
  13. b = b[:4]
  14. return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
  15. }
  16. func load64(b []byte, i int) uint64 {
  17. b = b[i:]
  18. b = b[:8]
  19. return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
  20. uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
  21. }
  22. // hash6 returns the hash of the lowest 6 bytes of u to fit in a hash table with h bits.
  23. // Preferably h should be a constant and should always be <64.
  24. func hash6(u uint64, h uint8) uint32 {
  25. const prime6bytes = 227718039650203
  26. return uint32(((u << (64 - 48)) * prime6bytes) >> ((64 - h) & 63))
  27. }
  28. func encodeGo(dst, src []byte) []byte {
  29. if n := MaxEncodedLen(len(src)); n < 0 {
  30. panic(ErrTooLarge)
  31. } else if len(dst) < n {
  32. dst = make([]byte, n)
  33. }
  34. // The block starts with the varint-encoded length of the decompressed bytes.
  35. d := binary.PutUvarint(dst, uint64(len(src)))
  36. if len(src) == 0 {
  37. return dst[:d]
  38. }
  39. if len(src) < minNonLiteralBlockSize {
  40. d += emitLiteral(dst[d:], src)
  41. return dst[:d]
  42. }
  43. n := encodeBlockGo(dst[d:], src)
  44. if n > 0 {
  45. d += n
  46. return dst[:d]
  47. }
  48. // Not compressible
  49. d += emitLiteral(dst[d:], src)
  50. return dst[:d]
  51. }
  52. // encodeBlockGo encodes a non-empty src to a guaranteed-large-enough dst. It
  53. // assumes that the varint-encoded length of the decompressed bytes has already
  54. // been written.
  55. //
  56. // It also assumes that:
  57. // len(dst) >= MaxEncodedLen(len(src)) &&
  58. // minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
  59. func encodeBlockGo(dst, src []byte) (d int) {
  60. // Initialize the hash table.
  61. const (
  62. tableBits = 14
  63. maxTableSize = 1 << tableBits
  64. )
  65. var table [maxTableSize]uint32
  66. // sLimit is when to stop looking for offset/length copies. The inputMargin
  67. // lets us use a fast path for emitLiteral in the main loop, while we are
  68. // looking for copies.
  69. sLimit := len(src) - inputMargin
  70. // Bail if we can't compress to at least this.
  71. dstLimit := len(src) - len(src)>>5 - 5
  72. // nextEmit is where in src the next emitLiteral should start from.
  73. nextEmit := 0
  74. // The encoded form must start with a literal, as there are no previous
  75. // bytes to copy, so we start looking for hash matches at s == 1.
  76. s := 1
  77. cv := load64(src, s)
  78. // We search for a repeat at -1, but don't output repeats when nextEmit == 0
  79. repeat := 1
  80. for {
  81. candidate := 0
  82. for {
  83. // Next src position to check
  84. nextS := s + (s-nextEmit)>>6 + 4
  85. if nextS > sLimit {
  86. goto emitRemainder
  87. }
  88. hash0 := hash6(cv, tableBits)
  89. hash1 := hash6(cv>>8, tableBits)
  90. candidate = int(table[hash0])
  91. candidate2 := int(table[hash1])
  92. table[hash0] = uint32(s)
  93. table[hash1] = uint32(s + 1)
  94. hash2 := hash6(cv>>16, tableBits)
  95. // Check repeat at offset checkRep.
  96. const checkRep = 1
  97. if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
  98. base := s + checkRep
  99. // Extend back
  100. for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
  101. i--
  102. base--
  103. }
  104. d += emitLiteral(dst[d:], src[nextEmit:base])
  105. // Extend forward
  106. candidate := s - repeat + 4 + checkRep
  107. s += 4 + checkRep
  108. for s <= sLimit {
  109. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  110. s += bits.TrailingZeros64(diff) >> 3
  111. break
  112. }
  113. s += 8
  114. candidate += 8
  115. }
  116. if nextEmit > 0 {
  117. // same as `add := emitCopy(dst[d:], repeat, s-base)` but skips storing offset.
  118. d += emitRepeat(dst[d:], repeat, s-base)
  119. } else {
  120. // First match, cannot be repeat.
  121. d += emitCopy(dst[d:], repeat, s-base)
  122. }
  123. nextEmit = s
  124. if s >= sLimit {
  125. goto emitRemainder
  126. }
  127. cv = load64(src, s)
  128. continue
  129. }
  130. if uint32(cv) == load32(src, candidate) {
  131. break
  132. }
  133. candidate = int(table[hash2])
  134. if uint32(cv>>8) == load32(src, candidate2) {
  135. table[hash2] = uint32(s + 2)
  136. candidate = candidate2
  137. s++
  138. break
  139. }
  140. table[hash2] = uint32(s + 2)
  141. if uint32(cv>>16) == load32(src, candidate) {
  142. s += 2
  143. break
  144. }
  145. cv = load64(src, nextS)
  146. s = nextS
  147. }
  148. // Extend backwards
  149. for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
  150. candidate--
  151. s--
  152. }
  153. // Bail if we exceed the maximum size.
  154. if d+(s-nextEmit) > dstLimit {
  155. return 0
  156. }
  157. // A 4-byte match has been found. We'll later see if more than 4 bytes
  158. // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
  159. // them as literal bytes.
  160. d += emitLiteral(dst[d:], src[nextEmit:s])
  161. // Call emitCopy, and then see if another emitCopy could be our next
  162. // move. Repeat until we find no match for the input immediately after
  163. // what was consumed by the last emitCopy call.
  164. //
  165. // If we exit this loop normally then we need to call emitLiteral next,
  166. // though we don't yet know how big the literal will be. We handle that
  167. // by proceeding to the next iteration of the main loop. We also can
  168. // exit this loop via goto if we get close to exhausting the input.
  169. for {
  170. // Invariant: we have a 4-byte match at s, and no need to emit any
  171. // literal bytes prior to s.
  172. base := s
  173. repeat = base - candidate
  174. // Extend the 4-byte match as long as possible.
  175. s += 4
  176. candidate += 4
  177. for s <= len(src)-8 {
  178. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  179. s += bits.TrailingZeros64(diff) >> 3
  180. break
  181. }
  182. s += 8
  183. candidate += 8
  184. }
  185. d += emitCopy(dst[d:], repeat, s-base)
  186. if false {
  187. // Validate match.
  188. a := src[base:s]
  189. b := src[base-repeat : base-repeat+(s-base)]
  190. if !bytes.Equal(a, b) {
  191. panic("mismatch")
  192. }
  193. }
  194. nextEmit = s
  195. if s >= sLimit {
  196. goto emitRemainder
  197. }
  198. if d > dstLimit {
  199. // Do we have space for more, if not bail.
  200. return 0
  201. }
  202. // Check for an immediate match, otherwise start search at s+1
  203. x := load64(src, s-2)
  204. m2Hash := hash6(x, tableBits)
  205. currHash := hash6(x>>16, tableBits)
  206. candidate = int(table[currHash])
  207. table[m2Hash] = uint32(s - 2)
  208. table[currHash] = uint32(s)
  209. if uint32(x>>16) != load32(src, candidate) {
  210. cv = load64(src, s+1)
  211. s++
  212. break
  213. }
  214. }
  215. }
  216. emitRemainder:
  217. if nextEmit < len(src) {
  218. // Bail if we exceed the maximum size.
  219. if d+len(src)-nextEmit > dstLimit {
  220. return 0
  221. }
  222. d += emitLiteral(dst[d:], src[nextEmit:])
  223. }
  224. return d
  225. }