encode_go.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. //go:build !amd64 || appengine || !gc || noasm
  2. // +build !amd64 appengine !gc noasm
  3. package s2
  4. import (
  5. "bytes"
  6. "math/bits"
  7. )
  8. const hasAmd64Asm = false
  9. // encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It
  10. // assumes that the varint-encoded length of the decompressed bytes has already
  11. // been written.
  12. //
  13. // It also assumes that:
  14. //
  15. // len(dst) >= MaxEncodedLen(len(src))
  16. func encodeBlock(dst, src []byte) (d int) {
  17. if len(src) < minNonLiteralBlockSize {
  18. return 0
  19. }
  20. return encodeBlockGo(dst, src)
  21. }
  22. // encodeBlockBetter encodes a non-empty src to a guaranteed-large-enough dst. It
  23. // assumes that the varint-encoded length of the decompressed bytes has already
  24. // been written.
  25. //
  26. // It also assumes that:
  27. //
  28. // len(dst) >= MaxEncodedLen(len(src))
  29. func encodeBlockBetter(dst, src []byte) (d int) {
  30. return encodeBlockBetterGo(dst, src)
  31. }
  32. // encodeBlockBetter encodes a non-empty src to a guaranteed-large-enough dst. It
  33. // assumes that the varint-encoded length of the decompressed bytes has already
  34. // been written.
  35. //
  36. // It also assumes that:
  37. //
  38. // len(dst) >= MaxEncodedLen(len(src))
  39. func encodeBlockBetterSnappy(dst, src []byte) (d int) {
  40. return encodeBlockBetterSnappyGo(dst, src)
  41. }
  42. // encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It
  43. // assumes that the varint-encoded length of the decompressed bytes has already
  44. // been written.
  45. //
  46. // It also assumes that:
  47. //
  48. // len(dst) >= MaxEncodedLen(len(src))
  49. func encodeBlockSnappy(dst, src []byte) (d int) {
  50. if len(src) < minNonLiteralBlockSize {
  51. return 0
  52. }
  53. return encodeBlockSnappyGo(dst, src)
  54. }
  55. // emitLiteral writes a literal chunk and returns the number of bytes written.
  56. //
  57. // It assumes that:
  58. //
  59. // dst is long enough to hold the encoded bytes
  60. // 0 <= len(lit) && len(lit) <= math.MaxUint32
  61. func emitLiteral(dst, lit []byte) int {
  62. if len(lit) == 0 {
  63. return 0
  64. }
  65. const num = 63<<2 | tagLiteral
  66. i, n := 0, uint(len(lit)-1)
  67. switch {
  68. case n < 60:
  69. dst[0] = uint8(n)<<2 | tagLiteral
  70. i = 1
  71. case n < 1<<8:
  72. dst[1] = uint8(n)
  73. dst[0] = 60<<2 | tagLiteral
  74. i = 2
  75. case n < 1<<16:
  76. dst[2] = uint8(n >> 8)
  77. dst[1] = uint8(n)
  78. dst[0] = 61<<2 | tagLiteral
  79. i = 3
  80. case n < 1<<24:
  81. dst[3] = uint8(n >> 16)
  82. dst[2] = uint8(n >> 8)
  83. dst[1] = uint8(n)
  84. dst[0] = 62<<2 | tagLiteral
  85. i = 4
  86. default:
  87. dst[4] = uint8(n >> 24)
  88. dst[3] = uint8(n >> 16)
  89. dst[2] = uint8(n >> 8)
  90. dst[1] = uint8(n)
  91. dst[0] = 63<<2 | tagLiteral
  92. i = 5
  93. }
  94. return i + copy(dst[i:], lit)
  95. }
  96. // emitRepeat writes a repeat chunk and returns the number of bytes written.
  97. // Length must be at least 4 and < 1<<24
  98. func emitRepeat(dst []byte, offset, length int) int {
  99. // Repeat offset, make length cheaper
  100. length -= 4
  101. if length <= 4 {
  102. dst[0] = uint8(length)<<2 | tagCopy1
  103. dst[1] = 0
  104. return 2
  105. }
  106. if length < 8 && offset < 2048 {
  107. // Encode WITH offset
  108. dst[1] = uint8(offset)
  109. dst[0] = uint8(offset>>8)<<5 | uint8(length)<<2 | tagCopy1
  110. return 2
  111. }
  112. if length < (1<<8)+4 {
  113. length -= 4
  114. dst[2] = uint8(length)
  115. dst[1] = 0
  116. dst[0] = 5<<2 | tagCopy1
  117. return 3
  118. }
  119. if length < (1<<16)+(1<<8) {
  120. length -= 1 << 8
  121. dst[3] = uint8(length >> 8)
  122. dst[2] = uint8(length >> 0)
  123. dst[1] = 0
  124. dst[0] = 6<<2 | tagCopy1
  125. return 4
  126. }
  127. const maxRepeat = (1 << 24) - 1
  128. length -= 1 << 16
  129. left := 0
  130. if length > maxRepeat {
  131. left = length - maxRepeat + 4
  132. length = maxRepeat - 4
  133. }
  134. dst[4] = uint8(length >> 16)
  135. dst[3] = uint8(length >> 8)
  136. dst[2] = uint8(length >> 0)
  137. dst[1] = 0
  138. dst[0] = 7<<2 | tagCopy1
  139. if left > 0 {
  140. return 5 + emitRepeat(dst[5:], offset, left)
  141. }
  142. return 5
  143. }
  144. // emitCopy writes a copy chunk and returns the number of bytes written.
  145. //
  146. // It assumes that:
  147. //
  148. // dst is long enough to hold the encoded bytes
  149. // 1 <= offset && offset <= math.MaxUint32
  150. // 4 <= length && length <= 1 << 24
  151. func emitCopy(dst []byte, offset, length int) int {
  152. if offset >= 65536 {
  153. i := 0
  154. if length > 64 {
  155. // Emit a length 64 copy, encoded as 5 bytes.
  156. dst[4] = uint8(offset >> 24)
  157. dst[3] = uint8(offset >> 16)
  158. dst[2] = uint8(offset >> 8)
  159. dst[1] = uint8(offset)
  160. dst[0] = 63<<2 | tagCopy4
  161. length -= 64
  162. if length >= 4 {
  163. // Emit remaining as repeats
  164. return 5 + emitRepeat(dst[5:], offset, length)
  165. }
  166. i = 5
  167. }
  168. if length == 0 {
  169. return i
  170. }
  171. // Emit a copy, offset encoded as 4 bytes.
  172. dst[i+0] = uint8(length-1)<<2 | tagCopy4
  173. dst[i+1] = uint8(offset)
  174. dst[i+2] = uint8(offset >> 8)
  175. dst[i+3] = uint8(offset >> 16)
  176. dst[i+4] = uint8(offset >> 24)
  177. return i + 5
  178. }
  179. // Offset no more than 2 bytes.
  180. if length > 64 {
  181. off := 3
  182. if offset < 2048 {
  183. // emit 8 bytes as tagCopy1, rest as repeats.
  184. dst[1] = uint8(offset)
  185. dst[0] = uint8(offset>>8)<<5 | uint8(8-4)<<2 | tagCopy1
  186. length -= 8
  187. off = 2
  188. } else {
  189. // Emit a length 60 copy, encoded as 3 bytes.
  190. // Emit remaining as repeat value (minimum 4 bytes).
  191. dst[2] = uint8(offset >> 8)
  192. dst[1] = uint8(offset)
  193. dst[0] = 59<<2 | tagCopy2
  194. length -= 60
  195. }
  196. // Emit remaining as repeats, at least 4 bytes remain.
  197. return off + emitRepeat(dst[off:], offset, length)
  198. }
  199. if length >= 12 || offset >= 2048 {
  200. // Emit the remaining copy, encoded as 3 bytes.
  201. dst[2] = uint8(offset >> 8)
  202. dst[1] = uint8(offset)
  203. dst[0] = uint8(length-1)<<2 | tagCopy2
  204. return 3
  205. }
  206. // Emit the remaining copy, encoded as 2 bytes.
  207. dst[1] = uint8(offset)
  208. dst[0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
  209. return 2
  210. }
  211. // emitCopyNoRepeat writes a copy chunk and returns the number of bytes written.
  212. //
  213. // It assumes that:
  214. //
  215. // dst is long enough to hold the encoded bytes
  216. // 1 <= offset && offset <= math.MaxUint32
  217. // 4 <= length && length <= 1 << 24
  218. func emitCopyNoRepeat(dst []byte, offset, length int) int {
  219. if offset >= 65536 {
  220. i := 0
  221. if length > 64 {
  222. // Emit a length 64 copy, encoded as 5 bytes.
  223. dst[4] = uint8(offset >> 24)
  224. dst[3] = uint8(offset >> 16)
  225. dst[2] = uint8(offset >> 8)
  226. dst[1] = uint8(offset)
  227. dst[0] = 63<<2 | tagCopy4
  228. length -= 64
  229. if length >= 4 {
  230. // Emit remaining as repeats
  231. return 5 + emitCopyNoRepeat(dst[5:], offset, length)
  232. }
  233. i = 5
  234. }
  235. if length == 0 {
  236. return i
  237. }
  238. // Emit a copy, offset encoded as 4 bytes.
  239. dst[i+0] = uint8(length-1)<<2 | tagCopy4
  240. dst[i+1] = uint8(offset)
  241. dst[i+2] = uint8(offset >> 8)
  242. dst[i+3] = uint8(offset >> 16)
  243. dst[i+4] = uint8(offset >> 24)
  244. return i + 5
  245. }
  246. // Offset no more than 2 bytes.
  247. if length > 64 {
  248. // Emit a length 60 copy, encoded as 3 bytes.
  249. // Emit remaining as repeat value (minimum 4 bytes).
  250. dst[2] = uint8(offset >> 8)
  251. dst[1] = uint8(offset)
  252. dst[0] = 59<<2 | tagCopy2
  253. length -= 60
  254. // Emit remaining as repeats, at least 4 bytes remain.
  255. return 3 + emitCopyNoRepeat(dst[3:], offset, length)
  256. }
  257. if length >= 12 || offset >= 2048 {
  258. // Emit the remaining copy, encoded as 3 bytes.
  259. dst[2] = uint8(offset >> 8)
  260. dst[1] = uint8(offset)
  261. dst[0] = uint8(length-1)<<2 | tagCopy2
  262. return 3
  263. }
  264. // Emit the remaining copy, encoded as 2 bytes.
  265. dst[1] = uint8(offset)
  266. dst[0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
  267. return 2
  268. }
  269. // matchLen returns how many bytes match in a and b
  270. //
  271. // It assumes that:
  272. //
  273. // len(a) <= len(b)
  274. func matchLen(a []byte, b []byte) int {
  275. b = b[:len(a)]
  276. var checked int
  277. if len(a) > 4 {
  278. // Try 4 bytes first
  279. if diff := load32(a, 0) ^ load32(b, 0); diff != 0 {
  280. return bits.TrailingZeros32(diff) >> 3
  281. }
  282. // Switch to 8 byte matching.
  283. checked = 4
  284. a = a[4:]
  285. b = b[4:]
  286. for len(a) >= 8 {
  287. b = b[:len(a)]
  288. if diff := load64(a, 0) ^ load64(b, 0); diff != 0 {
  289. return checked + (bits.TrailingZeros64(diff) >> 3)
  290. }
  291. checked += 8
  292. a = a[8:]
  293. b = b[8:]
  294. }
  295. }
  296. b = b[:len(a)]
  297. for i := range a {
  298. if a[i] != b[i] {
  299. return int(i) + checked
  300. }
  301. }
  302. return len(a) + checked
  303. }
  304. func calcBlockSize(src []byte) (d int) {
  305. // Initialize the hash table.
  306. const (
  307. tableBits = 13
  308. maxTableSize = 1 << tableBits
  309. )
  310. var table [maxTableSize]uint32
  311. // sLimit is when to stop looking for offset/length copies. The inputMargin
  312. // lets us use a fast path for emitLiteral in the main loop, while we are
  313. // looking for copies.
  314. sLimit := len(src) - inputMargin
  315. // Bail if we can't compress to at least this.
  316. dstLimit := len(src) - len(src)>>5 - 5
  317. // nextEmit is where in src the next emitLiteral should start from.
  318. nextEmit := 0
  319. // The encoded form must start with a literal, as there are no previous
  320. // bytes to copy, so we start looking for hash matches at s == 1.
  321. s := 1
  322. cv := load64(src, s)
  323. // We search for a repeat at -1, but don't output repeats when nextEmit == 0
  324. repeat := 1
  325. for {
  326. candidate := 0
  327. for {
  328. // Next src position to check
  329. nextS := s + (s-nextEmit)>>6 + 4
  330. if nextS > sLimit {
  331. goto emitRemainder
  332. }
  333. hash0 := hash6(cv, tableBits)
  334. hash1 := hash6(cv>>8, tableBits)
  335. candidate = int(table[hash0])
  336. candidate2 := int(table[hash1])
  337. table[hash0] = uint32(s)
  338. table[hash1] = uint32(s + 1)
  339. hash2 := hash6(cv>>16, tableBits)
  340. // Check repeat at offset checkRep.
  341. const checkRep = 1
  342. if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
  343. base := s + checkRep
  344. // Extend back
  345. for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
  346. i--
  347. base--
  348. }
  349. d += emitLiteralSize(src[nextEmit:base])
  350. // Extend forward
  351. candidate := s - repeat + 4 + checkRep
  352. s += 4 + checkRep
  353. for s <= sLimit {
  354. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  355. s += bits.TrailingZeros64(diff) >> 3
  356. break
  357. }
  358. s += 8
  359. candidate += 8
  360. }
  361. d += emitCopyNoRepeatSize(repeat, s-base)
  362. nextEmit = s
  363. if s >= sLimit {
  364. goto emitRemainder
  365. }
  366. cv = load64(src, s)
  367. continue
  368. }
  369. if uint32(cv) == load32(src, candidate) {
  370. break
  371. }
  372. candidate = int(table[hash2])
  373. if uint32(cv>>8) == load32(src, candidate2) {
  374. table[hash2] = uint32(s + 2)
  375. candidate = candidate2
  376. s++
  377. break
  378. }
  379. table[hash2] = uint32(s + 2)
  380. if uint32(cv>>16) == load32(src, candidate) {
  381. s += 2
  382. break
  383. }
  384. cv = load64(src, nextS)
  385. s = nextS
  386. }
  387. // Extend backwards
  388. for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
  389. candidate--
  390. s--
  391. }
  392. // Bail if we exceed the maximum size.
  393. if d+(s-nextEmit) > dstLimit {
  394. return 0
  395. }
  396. // A 4-byte match has been found. We'll later see if more than 4 bytes
  397. // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
  398. // them as literal bytes.
  399. d += emitLiteralSize(src[nextEmit:s])
  400. // Call emitCopy, and then see if another emitCopy could be our next
  401. // move. Repeat until we find no match for the input immediately after
  402. // what was consumed by the last emitCopy call.
  403. //
  404. // If we exit this loop normally then we need to call emitLiteral next,
  405. // though we don't yet know how big the literal will be. We handle that
  406. // by proceeding to the next iteration of the main loop. We also can
  407. // exit this loop via goto if we get close to exhausting the input.
  408. for {
  409. // Invariant: we have a 4-byte match at s, and no need to emit any
  410. // literal bytes prior to s.
  411. base := s
  412. repeat = base - candidate
  413. // Extend the 4-byte match as long as possible.
  414. s += 4
  415. candidate += 4
  416. for s <= len(src)-8 {
  417. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  418. s += bits.TrailingZeros64(diff) >> 3
  419. break
  420. }
  421. s += 8
  422. candidate += 8
  423. }
  424. d += emitCopyNoRepeatSize(repeat, s-base)
  425. if false {
  426. // Validate match.
  427. a := src[base:s]
  428. b := src[base-repeat : base-repeat+(s-base)]
  429. if !bytes.Equal(a, b) {
  430. panic("mismatch")
  431. }
  432. }
  433. nextEmit = s
  434. if s >= sLimit {
  435. goto emitRemainder
  436. }
  437. if d > dstLimit {
  438. // Do we have space for more, if not bail.
  439. return 0
  440. }
  441. // Check for an immediate match, otherwise start search at s+1
  442. x := load64(src, s-2)
  443. m2Hash := hash6(x, tableBits)
  444. currHash := hash6(x>>16, tableBits)
  445. candidate = int(table[currHash])
  446. table[m2Hash] = uint32(s - 2)
  447. table[currHash] = uint32(s)
  448. if uint32(x>>16) != load32(src, candidate) {
  449. cv = load64(src, s+1)
  450. s++
  451. break
  452. }
  453. }
  454. }
  455. emitRemainder:
  456. if nextEmit < len(src) {
  457. // Bail if we exceed the maximum size.
  458. if d+len(src)-nextEmit > dstLimit {
  459. return 0
  460. }
  461. d += emitLiteralSize(src[nextEmit:])
  462. }
  463. return d
  464. }
  465. func calcBlockSizeSmall(src []byte) (d int) {
  466. // Initialize the hash table.
  467. const (
  468. tableBits = 9
  469. maxTableSize = 1 << tableBits
  470. )
  471. var table [maxTableSize]uint32
  472. // sLimit is when to stop looking for offset/length copies. The inputMargin
  473. // lets us use a fast path for emitLiteral in the main loop, while we are
  474. // looking for copies.
  475. sLimit := len(src) - inputMargin
  476. // Bail if we can't compress to at least this.
  477. dstLimit := len(src) - len(src)>>5 - 5
  478. // nextEmit is where in src the next emitLiteral should start from.
  479. nextEmit := 0
  480. // The encoded form must start with a literal, as there are no previous
  481. // bytes to copy, so we start looking for hash matches at s == 1.
  482. s := 1
  483. cv := load64(src, s)
  484. // We search for a repeat at -1, but don't output repeats when nextEmit == 0
  485. repeat := 1
  486. for {
  487. candidate := 0
  488. for {
  489. // Next src position to check
  490. nextS := s + (s-nextEmit)>>6 + 4
  491. if nextS > sLimit {
  492. goto emitRemainder
  493. }
  494. hash0 := hash6(cv, tableBits)
  495. hash1 := hash6(cv>>8, tableBits)
  496. candidate = int(table[hash0])
  497. candidate2 := int(table[hash1])
  498. table[hash0] = uint32(s)
  499. table[hash1] = uint32(s + 1)
  500. hash2 := hash6(cv>>16, tableBits)
  501. // Check repeat at offset checkRep.
  502. const checkRep = 1
  503. if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
  504. base := s + checkRep
  505. // Extend back
  506. for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
  507. i--
  508. base--
  509. }
  510. d += emitLiteralSize(src[nextEmit:base])
  511. // Extend forward
  512. candidate := s - repeat + 4 + checkRep
  513. s += 4 + checkRep
  514. for s <= sLimit {
  515. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  516. s += bits.TrailingZeros64(diff) >> 3
  517. break
  518. }
  519. s += 8
  520. candidate += 8
  521. }
  522. d += emitCopyNoRepeatSize(repeat, s-base)
  523. nextEmit = s
  524. if s >= sLimit {
  525. goto emitRemainder
  526. }
  527. cv = load64(src, s)
  528. continue
  529. }
  530. if uint32(cv) == load32(src, candidate) {
  531. break
  532. }
  533. candidate = int(table[hash2])
  534. if uint32(cv>>8) == load32(src, candidate2) {
  535. table[hash2] = uint32(s + 2)
  536. candidate = candidate2
  537. s++
  538. break
  539. }
  540. table[hash2] = uint32(s + 2)
  541. if uint32(cv>>16) == load32(src, candidate) {
  542. s += 2
  543. break
  544. }
  545. cv = load64(src, nextS)
  546. s = nextS
  547. }
  548. // Extend backwards
  549. for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
  550. candidate--
  551. s--
  552. }
  553. // Bail if we exceed the maximum size.
  554. if d+(s-nextEmit) > dstLimit {
  555. return 0
  556. }
  557. // A 4-byte match has been found. We'll later see if more than 4 bytes
  558. // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
  559. // them as literal bytes.
  560. d += emitLiteralSize(src[nextEmit:s])
  561. // Call emitCopy, and then see if another emitCopy could be our next
  562. // move. Repeat until we find no match for the input immediately after
  563. // what was consumed by the last emitCopy call.
  564. //
  565. // If we exit this loop normally then we need to call emitLiteral next,
  566. // though we don't yet know how big the literal will be. We handle that
  567. // by proceeding to the next iteration of the main loop. We also can
  568. // exit this loop via goto if we get close to exhausting the input.
  569. for {
  570. // Invariant: we have a 4-byte match at s, and no need to emit any
  571. // literal bytes prior to s.
  572. base := s
  573. repeat = base - candidate
  574. // Extend the 4-byte match as long as possible.
  575. s += 4
  576. candidate += 4
  577. for s <= len(src)-8 {
  578. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  579. s += bits.TrailingZeros64(diff) >> 3
  580. break
  581. }
  582. s += 8
  583. candidate += 8
  584. }
  585. d += emitCopyNoRepeatSize(repeat, s-base)
  586. if false {
  587. // Validate match.
  588. a := src[base:s]
  589. b := src[base-repeat : base-repeat+(s-base)]
  590. if !bytes.Equal(a, b) {
  591. panic("mismatch")
  592. }
  593. }
  594. nextEmit = s
  595. if s >= sLimit {
  596. goto emitRemainder
  597. }
  598. if d > dstLimit {
  599. // Do we have space for more, if not bail.
  600. return 0
  601. }
  602. // Check for an immediate match, otherwise start search at s+1
  603. x := load64(src, s-2)
  604. m2Hash := hash6(x, tableBits)
  605. currHash := hash6(x>>16, tableBits)
  606. candidate = int(table[currHash])
  607. table[m2Hash] = uint32(s - 2)
  608. table[currHash] = uint32(s)
  609. if uint32(x>>16) != load32(src, candidate) {
  610. cv = load64(src, s+1)
  611. s++
  612. break
  613. }
  614. }
  615. }
  616. emitRemainder:
  617. if nextEmit < len(src) {
  618. // Bail if we exceed the maximum size.
  619. if d+len(src)-nextEmit > dstLimit {
  620. return 0
  621. }
  622. d += emitLiteralSize(src[nextEmit:])
  623. }
  624. return d
  625. }
  626. // emitLiteral writes a literal chunk and returns the number of bytes written.
  627. //
  628. // It assumes that:
  629. //
  630. // dst is long enough to hold the encoded bytes
  631. // 0 <= len(lit) && len(lit) <= math.MaxUint32
  632. func emitLiteralSize(lit []byte) int {
  633. if len(lit) == 0 {
  634. return 0
  635. }
  636. switch {
  637. case len(lit) <= 60:
  638. return len(lit) + 1
  639. case len(lit) <= 1<<8:
  640. return len(lit) + 2
  641. case len(lit) <= 1<<16:
  642. return len(lit) + 3
  643. case len(lit) <= 1<<24:
  644. return len(lit) + 4
  645. default:
  646. return len(lit) + 5
  647. }
  648. }
  649. func cvtLZ4BlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
  650. panic("cvtLZ4BlockAsm should be unreachable")
  651. }
  652. func cvtLZ4BlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
  653. panic("cvtLZ4BlockSnappyAsm should be unreachable")
  654. }
  655. func cvtLZ4sBlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
  656. panic("cvtLZ4sBlockAsm should be unreachable")
  657. }
  658. func cvtLZ4sBlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
  659. panic("cvtLZ4sBlockSnappyAsm should be unreachable")
  660. }