encode.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. // Copyright 2011 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. "encoding/binary"
  8. "math"
  9. "math/bits"
  10. "sync"
  11. "github.com/klauspost/compress/internal/race"
  12. )
  13. // Encode returns the encoded form of src. The returned slice may be a sub-
  14. // slice of dst if dst was large enough to hold the entire encoded block.
  15. // Otherwise, a newly allocated slice will be returned.
  16. //
  17. // The dst and src must not overlap. It is valid to pass a nil dst.
  18. //
  19. // The blocks will require the same amount of memory to decode as encoding,
  20. // and does not make for concurrent decoding.
  21. // Also note that blocks do not contain CRC information, so corruption may be undetected.
  22. //
  23. // If you need to encode larger amounts of data, consider using
  24. // the streaming interface which gives all of these features.
  25. func Encode(dst, src []byte) []byte {
  26. if n := MaxEncodedLen(len(src)); n < 0 {
  27. panic(ErrTooLarge)
  28. } else if cap(dst) < n {
  29. dst = make([]byte, n)
  30. } else {
  31. dst = dst[:n]
  32. }
  33. // The block starts with the varint-encoded length of the decompressed bytes.
  34. d := binary.PutUvarint(dst, uint64(len(src)))
  35. if len(src) == 0 {
  36. return dst[:d]
  37. }
  38. if len(src) < minNonLiteralBlockSize {
  39. d += emitLiteral(dst[d:], src)
  40. return dst[:d]
  41. }
  42. n := encodeBlock(dst[d:], src)
  43. if n > 0 {
  44. d += n
  45. return dst[:d]
  46. }
  47. // Not compressible
  48. d += emitLiteral(dst[d:], src)
  49. return dst[:d]
  50. }
  51. var estblockPool [2]sync.Pool
  52. // EstimateBlockSize will perform a very fast compression
  53. // without outputting the result and return the compressed output size.
  54. // The function returns -1 if no improvement could be achieved.
  55. // Using actual compression will most often produce better compression than the estimate.
  56. func EstimateBlockSize(src []byte) (d int) {
  57. if len(src) <= inputMargin || int64(len(src)) > 0xffffffff {
  58. return -1
  59. }
  60. if len(src) <= 1024 {
  61. const sz, pool = 2048, 0
  62. tmp, ok := estblockPool[pool].Get().(*[sz]byte)
  63. if !ok {
  64. tmp = &[sz]byte{}
  65. }
  66. race.WriteSlice(tmp[:])
  67. defer estblockPool[pool].Put(tmp)
  68. d = calcBlockSizeSmall(src, tmp)
  69. } else {
  70. const sz, pool = 32768, 1
  71. tmp, ok := estblockPool[pool].Get().(*[sz]byte)
  72. if !ok {
  73. tmp = &[sz]byte{}
  74. }
  75. race.WriteSlice(tmp[:])
  76. defer estblockPool[pool].Put(tmp)
  77. d = calcBlockSize(src, tmp)
  78. }
  79. if d == 0 {
  80. return -1
  81. }
  82. // Size of the varint encoded block size.
  83. d += (bits.Len64(uint64(len(src))) + 7) / 7
  84. if d >= len(src) {
  85. return -1
  86. }
  87. return d
  88. }
  89. // EncodeBetter returns the encoded form of src. The returned slice may be a sub-
  90. // slice of dst if dst was large enough to hold the entire encoded block.
  91. // Otherwise, a newly allocated slice will be returned.
  92. //
  93. // EncodeBetter compresses better than Encode but typically with a
  94. // 10-40% speed decrease on both compression and decompression.
  95. //
  96. // The dst and src must not overlap. It is valid to pass a nil dst.
  97. //
  98. // The blocks will require the same amount of memory to decode as encoding,
  99. // and does not make for concurrent decoding.
  100. // Also note that blocks do not contain CRC information, so corruption may be undetected.
  101. //
  102. // If you need to encode larger amounts of data, consider using
  103. // the streaming interface which gives all of these features.
  104. func EncodeBetter(dst, src []byte) []byte {
  105. if n := MaxEncodedLen(len(src)); n < 0 {
  106. panic(ErrTooLarge)
  107. } else if len(dst) < n {
  108. dst = make([]byte, n)
  109. }
  110. // The block starts with the varint-encoded length of the decompressed bytes.
  111. d := binary.PutUvarint(dst, uint64(len(src)))
  112. if len(src) == 0 {
  113. return dst[:d]
  114. }
  115. if len(src) < minNonLiteralBlockSize {
  116. d += emitLiteral(dst[d:], src)
  117. return dst[:d]
  118. }
  119. n := encodeBlockBetter(dst[d:], src)
  120. if n > 0 {
  121. d += n
  122. return dst[:d]
  123. }
  124. // Not compressible
  125. d += emitLiteral(dst[d:], src)
  126. return dst[:d]
  127. }
  128. // EncodeBest returns the encoded form of src. The returned slice may be a sub-
  129. // slice of dst if dst was large enough to hold the entire encoded block.
  130. // Otherwise, a newly allocated slice will be returned.
  131. //
  132. // EncodeBest compresses as good as reasonably possible but with a
  133. // big speed decrease.
  134. //
  135. // The dst and src must not overlap. It is valid to pass a nil dst.
  136. //
  137. // The blocks will require the same amount of memory to decode as encoding,
  138. // and does not make for concurrent decoding.
  139. // Also note that blocks do not contain CRC information, so corruption may be undetected.
  140. //
  141. // If you need to encode larger amounts of data, consider using
  142. // the streaming interface which gives all of these features.
  143. func EncodeBest(dst, src []byte) []byte {
  144. if n := MaxEncodedLen(len(src)); n < 0 {
  145. panic(ErrTooLarge)
  146. } else if len(dst) < n {
  147. dst = make([]byte, n)
  148. }
  149. // The block starts with the varint-encoded length of the decompressed bytes.
  150. d := binary.PutUvarint(dst, uint64(len(src)))
  151. if len(src) == 0 {
  152. return dst[:d]
  153. }
  154. if len(src) < minNonLiteralBlockSize {
  155. d += emitLiteral(dst[d:], src)
  156. return dst[:d]
  157. }
  158. n := encodeBlockBest(dst[d:], src, nil)
  159. if n > 0 {
  160. d += n
  161. return dst[:d]
  162. }
  163. // Not compressible
  164. d += emitLiteral(dst[d:], src)
  165. return dst[:d]
  166. }
  167. // EncodeSnappy returns the encoded form of src. The returned slice may be a sub-
  168. // slice of dst if dst was large enough to hold the entire encoded block.
  169. // Otherwise, a newly allocated slice will be returned.
  170. //
  171. // The output is Snappy compatible and will likely decompress faster.
  172. //
  173. // The dst and src must not overlap. It is valid to pass a nil dst.
  174. //
  175. // The blocks will require the same amount of memory to decode as encoding,
  176. // and does not make for concurrent decoding.
  177. // Also note that blocks do not contain CRC information, so corruption may be undetected.
  178. //
  179. // If you need to encode larger amounts of data, consider using
  180. // the streaming interface which gives all of these features.
  181. func EncodeSnappy(dst, src []byte) []byte {
  182. if n := MaxEncodedLen(len(src)); n < 0 {
  183. panic(ErrTooLarge)
  184. } else if cap(dst) < n {
  185. dst = make([]byte, n)
  186. } else {
  187. dst = dst[:n]
  188. }
  189. // The block starts with the varint-encoded length of the decompressed bytes.
  190. d := binary.PutUvarint(dst, uint64(len(src)))
  191. if len(src) == 0 {
  192. return dst[:d]
  193. }
  194. if len(src) < minNonLiteralBlockSize {
  195. d += emitLiteral(dst[d:], src)
  196. return dst[:d]
  197. }
  198. n := encodeBlockSnappy(dst[d:], src)
  199. if n > 0 {
  200. d += n
  201. return dst[:d]
  202. }
  203. // Not compressible
  204. d += emitLiteral(dst[d:], src)
  205. return dst[:d]
  206. }
  207. // EncodeSnappyBetter returns the encoded form of src. The returned slice may be a sub-
  208. // slice of dst if dst was large enough to hold the entire encoded block.
  209. // Otherwise, a newly allocated slice will be returned.
  210. //
  211. // The output is Snappy compatible and will likely decompress faster.
  212. //
  213. // The dst and src must not overlap. It is valid to pass a nil dst.
  214. //
  215. // The blocks will require the same amount of memory to decode as encoding,
  216. // and does not make for concurrent decoding.
  217. // Also note that blocks do not contain CRC information, so corruption may be undetected.
  218. //
  219. // If you need to encode larger amounts of data, consider using
  220. // the streaming interface which gives all of these features.
  221. func EncodeSnappyBetter(dst, src []byte) []byte {
  222. if n := MaxEncodedLen(len(src)); n < 0 {
  223. panic(ErrTooLarge)
  224. } else if cap(dst) < n {
  225. dst = make([]byte, n)
  226. } else {
  227. dst = dst[:n]
  228. }
  229. // The block starts with the varint-encoded length of the decompressed bytes.
  230. d := binary.PutUvarint(dst, uint64(len(src)))
  231. if len(src) == 0 {
  232. return dst[:d]
  233. }
  234. if len(src) < minNonLiteralBlockSize {
  235. d += emitLiteral(dst[d:], src)
  236. return dst[:d]
  237. }
  238. n := encodeBlockBetterSnappy(dst[d:], src)
  239. if n > 0 {
  240. d += n
  241. return dst[:d]
  242. }
  243. // Not compressible
  244. d += emitLiteral(dst[d:], src)
  245. return dst[:d]
  246. }
  247. // EncodeSnappyBest returns the encoded form of src. The returned slice may be a sub-
  248. // slice of dst if dst was large enough to hold the entire encoded block.
  249. // Otherwise, a newly allocated slice will be returned.
  250. //
  251. // The output is Snappy compatible and will likely decompress faster.
  252. //
  253. // The dst and src must not overlap. It is valid to pass a nil dst.
  254. //
  255. // The blocks will require the same amount of memory to decode as encoding,
  256. // and does not make for concurrent decoding.
  257. // Also note that blocks do not contain CRC information, so corruption may be undetected.
  258. //
  259. // If you need to encode larger amounts of data, consider using
  260. // the streaming interface which gives all of these features.
  261. func EncodeSnappyBest(dst, src []byte) []byte {
  262. if n := MaxEncodedLen(len(src)); n < 0 {
  263. panic(ErrTooLarge)
  264. } else if cap(dst) < n {
  265. dst = make([]byte, n)
  266. } else {
  267. dst = dst[:n]
  268. }
  269. // The block starts with the varint-encoded length of the decompressed bytes.
  270. d := binary.PutUvarint(dst, uint64(len(src)))
  271. if len(src) == 0 {
  272. return dst[:d]
  273. }
  274. if len(src) < minNonLiteralBlockSize {
  275. d += emitLiteral(dst[d:], src)
  276. return dst[:d]
  277. }
  278. n := encodeBlockBestSnappy(dst[d:], src)
  279. if n > 0 {
  280. d += n
  281. return dst[:d]
  282. }
  283. // Not compressible
  284. d += emitLiteral(dst[d:], src)
  285. return dst[:d]
  286. }
  287. // ConcatBlocks will concatenate the supplied blocks and append them to the supplied destination.
  288. // If the destination is nil or too small, a new will be allocated.
  289. // The blocks are not validated, so garbage in = garbage out.
  290. // dst may not overlap block data.
  291. // Any data in dst is preserved as is, so it will not be considered a block.
  292. func ConcatBlocks(dst []byte, blocks ...[]byte) ([]byte, error) {
  293. totalSize := uint64(0)
  294. compSize := 0
  295. for _, b := range blocks {
  296. l, hdr, err := decodedLen(b)
  297. if err != nil {
  298. return nil, err
  299. }
  300. totalSize += uint64(l)
  301. compSize += len(b) - hdr
  302. }
  303. if totalSize == 0 {
  304. dst = append(dst, 0)
  305. return dst, nil
  306. }
  307. if totalSize > math.MaxUint32 {
  308. return nil, ErrTooLarge
  309. }
  310. var tmp [binary.MaxVarintLen32]byte
  311. hdrSize := binary.PutUvarint(tmp[:], totalSize)
  312. wantSize := hdrSize + compSize
  313. if cap(dst)-len(dst) < wantSize {
  314. dst = append(make([]byte, 0, wantSize+len(dst)), dst...)
  315. }
  316. dst = append(dst, tmp[:hdrSize]...)
  317. for _, b := range blocks {
  318. _, hdr, err := decodedLen(b)
  319. if err != nil {
  320. return nil, err
  321. }
  322. dst = append(dst, b[hdr:]...)
  323. }
  324. return dst, nil
  325. }
  326. // inputMargin is the minimum number of extra input bytes to keep, inside
  327. // encodeBlock's inner loop. On some architectures, this margin lets us
  328. // implement a fast path for emitLiteral, where the copy of short (<= 16 byte)
  329. // literals can be implemented as a single load to and store from a 16-byte
  330. // register. That literal's actual length can be as short as 1 byte, so this
  331. // can copy up to 15 bytes too much, but that's OK as subsequent iterations of
  332. // the encoding loop will fix up the copy overrun, and this inputMargin ensures
  333. // that we don't overrun the dst and src buffers.
  334. const inputMargin = 8
  335. // minNonLiteralBlockSize is the minimum size of the input to encodeBlock that
  336. // will be accepted by the encoder.
  337. const minNonLiteralBlockSize = 32
  338. const intReduction = 2 - (1 << (^uint(0) >> 63)) // 1 (32 bits) or 0 (64 bits)
  339. // MaxBlockSize is the maximum value where MaxEncodedLen will return a valid block size.
  340. // Blocks this big are highly discouraged, though.
  341. // Half the size on 32 bit systems.
  342. const MaxBlockSize = (1<<(32-intReduction) - 1) - binary.MaxVarintLen32 - 5
  343. // MaxEncodedLen returns the maximum length of a snappy block, given its
  344. // uncompressed length.
  345. //
  346. // It will return a negative value if srcLen is too large to encode.
  347. // 32 bit platforms will have lower thresholds for rejecting big content.
  348. func MaxEncodedLen(srcLen int) int {
  349. n := uint64(srcLen)
  350. if intReduction == 1 {
  351. // 32 bits
  352. if n > math.MaxInt32 {
  353. // Also includes negative.
  354. return -1
  355. }
  356. } else if n > 0xffffffff {
  357. // 64 bits
  358. // Also includes negative.
  359. return -1
  360. }
  361. // Size of the varint encoded block size.
  362. n = n + uint64((bits.Len64(n)+7)/7)
  363. // Add maximum size of encoding block as literals.
  364. n += uint64(literalExtraSize(int64(srcLen)))
  365. if intReduction == 1 {
  366. // 32 bits
  367. if n > math.MaxInt32 {
  368. return -1
  369. }
  370. } else if n > 0xffffffff {
  371. // 64 bits
  372. // Also includes negative.
  373. return -1
  374. }
  375. return int(n)
  376. }