encode_go.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  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. // input must be > inputMargin
  305. func calcBlockSize(src []byte) (d int) {
  306. // Initialize the hash table.
  307. const (
  308. tableBits = 13
  309. maxTableSize = 1 << tableBits
  310. )
  311. var table [maxTableSize]uint32
  312. // sLimit is when to stop looking for offset/length copies. The inputMargin
  313. // lets us use a fast path for emitLiteral in the main loop, while we are
  314. // looking for copies.
  315. sLimit := len(src) - inputMargin
  316. // Bail if we can't compress to at least this.
  317. dstLimit := len(src) - len(src)>>5 - 5
  318. // nextEmit is where in src the next emitLiteral should start from.
  319. nextEmit := 0
  320. // The encoded form must start with a literal, as there are no previous
  321. // bytes to copy, so we start looking for hash matches at s == 1.
  322. s := 1
  323. cv := load64(src, s)
  324. // We search for a repeat at -1, but don't output repeats when nextEmit == 0
  325. repeat := 1
  326. for {
  327. candidate := 0
  328. for {
  329. // Next src position to check
  330. nextS := s + (s-nextEmit)>>6 + 4
  331. if nextS > sLimit {
  332. goto emitRemainder
  333. }
  334. hash0 := hash6(cv, tableBits)
  335. hash1 := hash6(cv>>8, tableBits)
  336. candidate = int(table[hash0])
  337. candidate2 := int(table[hash1])
  338. table[hash0] = uint32(s)
  339. table[hash1] = uint32(s + 1)
  340. hash2 := hash6(cv>>16, tableBits)
  341. // Check repeat at offset checkRep.
  342. const checkRep = 1
  343. if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
  344. base := s + checkRep
  345. // Extend back
  346. for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
  347. i--
  348. base--
  349. }
  350. d += emitLiteralSize(src[nextEmit:base])
  351. // Extend forward
  352. candidate := s - repeat + 4 + checkRep
  353. s += 4 + checkRep
  354. for s <= sLimit {
  355. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  356. s += bits.TrailingZeros64(diff) >> 3
  357. break
  358. }
  359. s += 8
  360. candidate += 8
  361. }
  362. d += emitCopyNoRepeatSize(repeat, s-base)
  363. nextEmit = s
  364. if s >= sLimit {
  365. goto emitRemainder
  366. }
  367. cv = load64(src, s)
  368. continue
  369. }
  370. if uint32(cv) == load32(src, candidate) {
  371. break
  372. }
  373. candidate = int(table[hash2])
  374. if uint32(cv>>8) == load32(src, candidate2) {
  375. table[hash2] = uint32(s + 2)
  376. candidate = candidate2
  377. s++
  378. break
  379. }
  380. table[hash2] = uint32(s + 2)
  381. if uint32(cv>>16) == load32(src, candidate) {
  382. s += 2
  383. break
  384. }
  385. cv = load64(src, nextS)
  386. s = nextS
  387. }
  388. // Extend backwards
  389. for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
  390. candidate--
  391. s--
  392. }
  393. // Bail if we exceed the maximum size.
  394. if d+(s-nextEmit) > dstLimit {
  395. return 0
  396. }
  397. // A 4-byte match has been found. We'll later see if more than 4 bytes
  398. // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
  399. // them as literal bytes.
  400. d += emitLiteralSize(src[nextEmit:s])
  401. // Call emitCopy, and then see if another emitCopy could be our next
  402. // move. Repeat until we find no match for the input immediately after
  403. // what was consumed by the last emitCopy call.
  404. //
  405. // If we exit this loop normally then we need to call emitLiteral next,
  406. // though we don't yet know how big the literal will be. We handle that
  407. // by proceeding to the next iteration of the main loop. We also can
  408. // exit this loop via goto if we get close to exhausting the input.
  409. for {
  410. // Invariant: we have a 4-byte match at s, and no need to emit any
  411. // literal bytes prior to s.
  412. base := s
  413. repeat = base - candidate
  414. // Extend the 4-byte match as long as possible.
  415. s += 4
  416. candidate += 4
  417. for s <= len(src)-8 {
  418. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  419. s += bits.TrailingZeros64(diff) >> 3
  420. break
  421. }
  422. s += 8
  423. candidate += 8
  424. }
  425. d += emitCopyNoRepeatSize(repeat, s-base)
  426. if false {
  427. // Validate match.
  428. a := src[base:s]
  429. b := src[base-repeat : base-repeat+(s-base)]
  430. if !bytes.Equal(a, b) {
  431. panic("mismatch")
  432. }
  433. }
  434. nextEmit = s
  435. if s >= sLimit {
  436. goto emitRemainder
  437. }
  438. if d > dstLimit {
  439. // Do we have space for more, if not bail.
  440. return 0
  441. }
  442. // Check for an immediate match, otherwise start search at s+1
  443. x := load64(src, s-2)
  444. m2Hash := hash6(x, tableBits)
  445. currHash := hash6(x>>16, tableBits)
  446. candidate = int(table[currHash])
  447. table[m2Hash] = uint32(s - 2)
  448. table[currHash] = uint32(s)
  449. if uint32(x>>16) != load32(src, candidate) {
  450. cv = load64(src, s+1)
  451. s++
  452. break
  453. }
  454. }
  455. }
  456. emitRemainder:
  457. if nextEmit < len(src) {
  458. // Bail if we exceed the maximum size.
  459. if d+len(src)-nextEmit > dstLimit {
  460. return 0
  461. }
  462. d += emitLiteralSize(src[nextEmit:])
  463. }
  464. return d
  465. }
  466. // length must be > inputMargin.
  467. func calcBlockSizeSmall(src []byte) (d int) {
  468. // Initialize the hash table.
  469. const (
  470. tableBits = 9
  471. maxTableSize = 1 << tableBits
  472. )
  473. var table [maxTableSize]uint32
  474. // sLimit is when to stop looking for offset/length copies. The inputMargin
  475. // lets us use a fast path for emitLiteral in the main loop, while we are
  476. // looking for copies.
  477. sLimit := len(src) - inputMargin
  478. // Bail if we can't compress to at least this.
  479. dstLimit := len(src) - len(src)>>5 - 5
  480. // nextEmit is where in src the next emitLiteral should start from.
  481. nextEmit := 0
  482. // The encoded form must start with a literal, as there are no previous
  483. // bytes to copy, so we start looking for hash matches at s == 1.
  484. s := 1
  485. cv := load64(src, s)
  486. // We search for a repeat at -1, but don't output repeats when nextEmit == 0
  487. repeat := 1
  488. for {
  489. candidate := 0
  490. for {
  491. // Next src position to check
  492. nextS := s + (s-nextEmit)>>6 + 4
  493. if nextS > sLimit {
  494. goto emitRemainder
  495. }
  496. hash0 := hash6(cv, tableBits)
  497. hash1 := hash6(cv>>8, tableBits)
  498. candidate = int(table[hash0])
  499. candidate2 := int(table[hash1])
  500. table[hash0] = uint32(s)
  501. table[hash1] = uint32(s + 1)
  502. hash2 := hash6(cv>>16, tableBits)
  503. // Check repeat at offset checkRep.
  504. const checkRep = 1
  505. if uint32(cv>>(checkRep*8)) == load32(src, s-repeat+checkRep) {
  506. base := s + checkRep
  507. // Extend back
  508. for i := base - repeat; base > nextEmit && i > 0 && src[i-1] == src[base-1]; {
  509. i--
  510. base--
  511. }
  512. d += emitLiteralSize(src[nextEmit:base])
  513. // Extend forward
  514. candidate := s - repeat + 4 + checkRep
  515. s += 4 + checkRep
  516. for s <= sLimit {
  517. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  518. s += bits.TrailingZeros64(diff) >> 3
  519. break
  520. }
  521. s += 8
  522. candidate += 8
  523. }
  524. d += emitCopyNoRepeatSize(repeat, s-base)
  525. nextEmit = s
  526. if s >= sLimit {
  527. goto emitRemainder
  528. }
  529. cv = load64(src, s)
  530. continue
  531. }
  532. if uint32(cv) == load32(src, candidate) {
  533. break
  534. }
  535. candidate = int(table[hash2])
  536. if uint32(cv>>8) == load32(src, candidate2) {
  537. table[hash2] = uint32(s + 2)
  538. candidate = candidate2
  539. s++
  540. break
  541. }
  542. table[hash2] = uint32(s + 2)
  543. if uint32(cv>>16) == load32(src, candidate) {
  544. s += 2
  545. break
  546. }
  547. cv = load64(src, nextS)
  548. s = nextS
  549. }
  550. // Extend backwards
  551. for candidate > 0 && s > nextEmit && src[candidate-1] == src[s-1] {
  552. candidate--
  553. s--
  554. }
  555. // Bail if we exceed the maximum size.
  556. if d+(s-nextEmit) > dstLimit {
  557. return 0
  558. }
  559. // A 4-byte match has been found. We'll later see if more than 4 bytes
  560. // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
  561. // them as literal bytes.
  562. d += emitLiteralSize(src[nextEmit:s])
  563. // Call emitCopy, and then see if another emitCopy could be our next
  564. // move. Repeat until we find no match for the input immediately after
  565. // what was consumed by the last emitCopy call.
  566. //
  567. // If we exit this loop normally then we need to call emitLiteral next,
  568. // though we don't yet know how big the literal will be. We handle that
  569. // by proceeding to the next iteration of the main loop. We also can
  570. // exit this loop via goto if we get close to exhausting the input.
  571. for {
  572. // Invariant: we have a 4-byte match at s, and no need to emit any
  573. // literal bytes prior to s.
  574. base := s
  575. repeat = base - candidate
  576. // Extend the 4-byte match as long as possible.
  577. s += 4
  578. candidate += 4
  579. for s <= len(src)-8 {
  580. if diff := load64(src, s) ^ load64(src, candidate); diff != 0 {
  581. s += bits.TrailingZeros64(diff) >> 3
  582. break
  583. }
  584. s += 8
  585. candidate += 8
  586. }
  587. d += emitCopyNoRepeatSize(repeat, s-base)
  588. if false {
  589. // Validate match.
  590. a := src[base:s]
  591. b := src[base-repeat : base-repeat+(s-base)]
  592. if !bytes.Equal(a, b) {
  593. panic("mismatch")
  594. }
  595. }
  596. nextEmit = s
  597. if s >= sLimit {
  598. goto emitRemainder
  599. }
  600. if d > dstLimit {
  601. // Do we have space for more, if not bail.
  602. return 0
  603. }
  604. // Check for an immediate match, otherwise start search at s+1
  605. x := load64(src, s-2)
  606. m2Hash := hash6(x, tableBits)
  607. currHash := hash6(x>>16, tableBits)
  608. candidate = int(table[currHash])
  609. table[m2Hash] = uint32(s - 2)
  610. table[currHash] = uint32(s)
  611. if uint32(x>>16) != load32(src, candidate) {
  612. cv = load64(src, s+1)
  613. s++
  614. break
  615. }
  616. }
  617. }
  618. emitRemainder:
  619. if nextEmit < len(src) {
  620. // Bail if we exceed the maximum size.
  621. if d+len(src)-nextEmit > dstLimit {
  622. return 0
  623. }
  624. d += emitLiteralSize(src[nextEmit:])
  625. }
  626. return d
  627. }
  628. // emitLiteral writes a literal chunk and returns the number of bytes written.
  629. //
  630. // It assumes that:
  631. //
  632. // dst is long enough to hold the encoded bytes
  633. // 0 <= len(lit) && len(lit) <= math.MaxUint32
  634. func emitLiteralSize(lit []byte) int {
  635. if len(lit) == 0 {
  636. return 0
  637. }
  638. switch {
  639. case len(lit) <= 60:
  640. return len(lit) + 1
  641. case len(lit) <= 1<<8:
  642. return len(lit) + 2
  643. case len(lit) <= 1<<16:
  644. return len(lit) + 3
  645. case len(lit) <= 1<<24:
  646. return len(lit) + 4
  647. default:
  648. return len(lit) + 5
  649. }
  650. }
  651. func cvtLZ4BlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
  652. panic("cvtLZ4BlockAsm should be unreachable")
  653. }
  654. func cvtLZ4BlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
  655. panic("cvtLZ4BlockSnappyAsm should be unreachable")
  656. }
  657. func cvtLZ4sBlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
  658. panic("cvtLZ4sBlockAsm should be unreachable")
  659. }
  660. func cvtLZ4sBlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
  661. panic("cvtLZ4sBlockSnappyAsm should be unreachable")
  662. }