gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

encode_go.go (18081B)


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