encode.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  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 cap(dst) < n {
  108. dst = make([]byte, n)
  109. } else {
  110. dst = dst[:n]
  111. }
  112. // The block starts with the varint-encoded length of the decompressed bytes.
  113. d := binary.PutUvarint(dst, uint64(len(src)))
  114. if len(src) == 0 {
  115. return dst[:d]
  116. }
  117. if len(src) < minNonLiteralBlockSize {
  118. d += emitLiteral(dst[d:], src)
  119. return dst[:d]
  120. }
  121. n := encodeBlockBetter(dst[d:], src)
  122. if n > 0 {
  123. d += n
  124. return dst[:d]
  125. }
  126. // Not compressible
  127. d += emitLiteral(dst[d:], src)
  128. return dst[:d]
  129. }
  130. // EncodeBest returns the encoded form of src. The returned slice may be a sub-
  131. // slice of dst if dst was large enough to hold the entire encoded block.
  132. // Otherwise, a newly allocated slice will be returned.
  133. //
  134. // EncodeBest compresses as good as reasonably possible but with a
  135. // big speed decrease.
  136. //
  137. // The dst and src must not overlap. It is valid to pass a nil dst.
  138. //
  139. // The blocks will require the same amount of memory to decode as encoding,
  140. // and does not make for concurrent decoding.
  141. // Also note that blocks do not contain CRC information, so corruption may be undetected.
  142. //
  143. // If you need to encode larger amounts of data, consider using
  144. // the streaming interface which gives all of these features.
  145. func EncodeBest(dst, src []byte) []byte {
  146. if n := MaxEncodedLen(len(src)); n < 0 {
  147. panic(ErrTooLarge)
  148. } else if cap(dst) < n {
  149. dst = make([]byte, n)
  150. } else {
  151. dst = dst[:n]
  152. }
  153. // The block starts with the varint-encoded length of the decompressed bytes.
  154. d := binary.PutUvarint(dst, uint64(len(src)))
  155. if len(src) == 0 {
  156. return dst[:d]
  157. }
  158. if len(src) < minNonLiteralBlockSize {
  159. d += emitLiteral(dst[d:], src)
  160. return dst[:d]
  161. }
  162. n := encodeBlockBest(dst[d:], src, nil)
  163. if n > 0 {
  164. d += n
  165. return dst[:d]
  166. }
  167. // Not compressible
  168. d += emitLiteral(dst[d:], src)
  169. return dst[:d]
  170. }
  171. // EncodeSnappy returns the encoded form of src. The returned slice may be a sub-
  172. // slice of dst if dst was large enough to hold the entire encoded block.
  173. // Otherwise, a newly allocated slice will be returned.
  174. //
  175. // The output is Snappy compatible and will likely decompress faster.
  176. //
  177. // The dst and src must not overlap. It is valid to pass a nil dst.
  178. //
  179. // The blocks will require the same amount of memory to decode as encoding,
  180. // and does not make for concurrent decoding.
  181. // Also note that blocks do not contain CRC information, so corruption may be undetected.
  182. //
  183. // If you need to encode larger amounts of data, consider using
  184. // the streaming interface which gives all of these features.
  185. func EncodeSnappy(dst, src []byte) []byte {
  186. if n := MaxEncodedLen(len(src)); n < 0 {
  187. panic(ErrTooLarge)
  188. } else if cap(dst) < n {
  189. dst = make([]byte, n)
  190. } else {
  191. dst = dst[:n]
  192. }
  193. // The block starts with the varint-encoded length of the decompressed bytes.
  194. d := binary.PutUvarint(dst, uint64(len(src)))
  195. if len(src) == 0 {
  196. return dst[:d]
  197. }
  198. if len(src) < minNonLiteralBlockSize {
  199. d += emitLiteral(dst[d:], src)
  200. return dst[:d]
  201. }
  202. n := encodeBlockSnappy(dst[d:], src)
  203. if n > 0 {
  204. d += n
  205. return dst[:d]
  206. }
  207. // Not compressible
  208. d += emitLiteral(dst[d:], src)
  209. return dst[:d]
  210. }
  211. // EncodeSnappyBetter returns the encoded form of src. The returned slice may be a sub-
  212. // slice of dst if dst was large enough to hold the entire encoded block.
  213. // Otherwise, a newly allocated slice will be returned.
  214. //
  215. // The output is Snappy compatible and will likely decompress faster.
  216. //
  217. // The dst and src must not overlap. It is valid to pass a nil dst.
  218. //
  219. // The blocks will require the same amount of memory to decode as encoding,
  220. // and does not make for concurrent decoding.
  221. // Also note that blocks do not contain CRC information, so corruption may be undetected.
  222. //
  223. // If you need to encode larger amounts of data, consider using
  224. // the streaming interface which gives all of these features.
  225. func EncodeSnappyBetter(dst, src []byte) []byte {
  226. if n := MaxEncodedLen(len(src)); n < 0 {
  227. panic(ErrTooLarge)
  228. } else if cap(dst) < n {
  229. dst = make([]byte, n)
  230. } else {
  231. dst = dst[:n]
  232. }
  233. // The block starts with the varint-encoded length of the decompressed bytes.
  234. d := binary.PutUvarint(dst, uint64(len(src)))
  235. if len(src) == 0 {
  236. return dst[:d]
  237. }
  238. if len(src) < minNonLiteralBlockSize {
  239. d += emitLiteral(dst[d:], src)
  240. return dst[:d]
  241. }
  242. n := encodeBlockBetterSnappy(dst[d:], src)
  243. if n > 0 {
  244. d += n
  245. return dst[:d]
  246. }
  247. // Not compressible
  248. d += emitLiteral(dst[d:], src)
  249. return dst[:d]
  250. }
  251. // EncodeSnappyBest returns the encoded form of src. The returned slice may be a sub-
  252. // slice of dst if dst was large enough to hold the entire encoded block.
  253. // Otherwise, a newly allocated slice will be returned.
  254. //
  255. // The output is Snappy compatible and will likely decompress faster.
  256. //
  257. // The dst and src must not overlap. It is valid to pass a nil dst.
  258. //
  259. // The blocks will require the same amount of memory to decode as encoding,
  260. // and does not make for concurrent decoding.
  261. // Also note that blocks do not contain CRC information, so corruption may be undetected.
  262. //
  263. // If you need to encode larger amounts of data, consider using
  264. // the streaming interface which gives all of these features.
  265. func EncodeSnappyBest(dst, src []byte) []byte {
  266. if n := MaxEncodedLen(len(src)); n < 0 {
  267. panic(ErrTooLarge)
  268. } else if cap(dst) < n {
  269. dst = make([]byte, n)
  270. } else {
  271. dst = dst[:n]
  272. }
  273. // The block starts with the varint-encoded length of the decompressed bytes.
  274. d := binary.PutUvarint(dst, uint64(len(src)))
  275. if len(src) == 0 {
  276. return dst[:d]
  277. }
  278. if len(src) < minNonLiteralBlockSize {
  279. d += emitLiteral(dst[d:], src)
  280. return dst[:d]
  281. }
  282. n := encodeBlockBestSnappy(dst[d:], src)
  283. if n > 0 {
  284. d += n
  285. return dst[:d]
  286. }
  287. // Not compressible
  288. d += emitLiteral(dst[d:], src)
  289. return dst[:d]
  290. }
  291. // ConcatBlocks will concatenate the supplied blocks and append them to the supplied destination.
  292. // If the destination is nil or too small, a new will be allocated.
  293. // The blocks are not validated, so garbage in = garbage out.
  294. // dst may not overlap block data.
  295. // Any data in dst is preserved as is, so it will not be considered a block.
  296. func ConcatBlocks(dst []byte, blocks ...[]byte) ([]byte, error) {
  297. totalSize := uint64(0)
  298. compSize := 0
  299. for _, b := range blocks {
  300. l, hdr, err := decodedLen(b)
  301. if err != nil {
  302. return nil, err
  303. }
  304. totalSize += uint64(l)
  305. compSize += len(b) - hdr
  306. }
  307. if totalSize == 0 {
  308. dst = append(dst, 0)
  309. return dst, nil
  310. }
  311. if totalSize > math.MaxUint32 {
  312. return nil, ErrTooLarge
  313. }
  314. var tmp [binary.MaxVarintLen32]byte
  315. hdrSize := binary.PutUvarint(tmp[:], totalSize)
  316. wantSize := hdrSize + compSize
  317. if cap(dst)-len(dst) < wantSize {
  318. dst = append(make([]byte, 0, wantSize+len(dst)), dst...)
  319. }
  320. dst = append(dst, tmp[:hdrSize]...)
  321. for _, b := range blocks {
  322. _, hdr, err := decodedLen(b)
  323. if err != nil {
  324. return nil, err
  325. }
  326. dst = append(dst, b[hdr:]...)
  327. }
  328. return dst, nil
  329. }
  330. // inputMargin is the minimum number of extra input bytes to keep, inside
  331. // encodeBlock's inner loop. On some architectures, this margin lets us
  332. // implement a fast path for emitLiteral, where the copy of short (<= 16 byte)
  333. // literals can be implemented as a single load to and store from a 16-byte
  334. // register. That literal's actual length can be as short as 1 byte, so this
  335. // can copy up to 15 bytes too much, but that's OK as subsequent iterations of
  336. // the encoding loop will fix up the copy overrun, and this inputMargin ensures
  337. // that we don't overrun the dst and src buffers.
  338. const inputMargin = 8
  339. // minNonLiteralBlockSize is the minimum size of the input to encodeBlock that
  340. // will be accepted by the encoder.
  341. const minNonLiteralBlockSize = 32
  342. const intReduction = 2 - (1 << (^uint(0) >> 63)) // 1 (32 bits) or 0 (64 bits)
  343. // MaxBlockSize is the maximum value where MaxEncodedLen will return a valid block size.
  344. // Blocks this big are highly discouraged, though.
  345. // Half the size on 32 bit systems.
  346. const MaxBlockSize = (1<<(32-intReduction) - 1) - binary.MaxVarintLen32 - 5
  347. // MaxEncodedLen returns the maximum length of a snappy block, given its
  348. // uncompressed length.
  349. //
  350. // It will return a negative value if srcLen is too large to encode.
  351. // 32 bit platforms will have lower thresholds for rejecting big content.
  352. func MaxEncodedLen(srcLen int) int {
  353. n := uint64(srcLen)
  354. if intReduction == 1 {
  355. // 32 bits
  356. if n > math.MaxInt32 {
  357. // Also includes negative.
  358. return -1
  359. }
  360. } else if n > 0xffffffff {
  361. // 64 bits
  362. // Also includes negative.
  363. return -1
  364. }
  365. // Size of the varint encoded block size.
  366. n = n + uint64((bits.Len64(n)+7)/7)
  367. // Add maximum size of encoding block as literals.
  368. n += uint64(literalExtraSize(int64(srcLen)))
  369. if intReduction == 1 {
  370. // 32 bits
  371. if n > math.MaxInt32 {
  372. return -1
  373. }
  374. } else if n > 0xffffffff {
  375. // 64 bits
  376. // Also includes negative.
  377. return -1
  378. }
  379. return int(n)
  380. }