// Copyright 2011 The Snappy-Go Authors. All rights reserved.
// Copyright (c) 2019 Klaus Post. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package s2

import (
	
	
	
	

	
)

// Encode returns the encoded form of src. The returned slice may be a sub-
// slice of dst if dst was large enough to hold the entire encoded block.
// Otherwise, a newly allocated slice will be returned.
//
// The dst and src must not overlap. It is valid to pass a nil dst.
//
// The blocks will require the same amount of memory to decode as encoding,
// and does not make for concurrent decoding.
// Also note that blocks do not contain CRC information, so corruption may be undetected.
//
// If you need to encode larger amounts of data, consider using
// the streaming interface which gives all of these features.
func (,  []byte) []byte {
	if  := MaxEncodedLen(len());  < 0 {
		panic(ErrTooLarge)
	} else if cap() <  {
		 = make([]byte, )
	} else {
		 = [:]
	}

	// The block starts with the varint-encoded length of the decompressed bytes.
	 := binary.PutUvarint(, uint64(len()))

	if len() == 0 {
		return [:]
	}
	if len() < minNonLiteralBlockSize {
		 += emitLiteral([:], )
		return [:]
	}
	 := encodeBlock([:], )
	if  > 0 {
		 += 
		return [:]
	}
	// Not compressible
	 += emitLiteral([:], )
	return [:]
}

var estblockPool [2]sync.Pool

// EstimateBlockSize will perform a very fast compression
// without outputting the result and return the compressed output size.
// The function returns -1 if no improvement could be achieved.
// Using actual compression will most often produce better compression than the estimate.
func ( []byte) ( int) {
	if len() <= inputMargin || int64(len()) > 0xffffffff {
		return -1
	}
	if len() <= 1024 {
		const ,  = 2048, 0
		,  := estblockPool[].Get().(*[]byte)
		if ! {
			 = &[]byte{}
		}
		race.WriteSlice([:])
		defer estblockPool[].Put()

		 = calcBlockSizeSmall(, )
	} else {
		const ,  = 32768, 1
		,  := estblockPool[].Get().(*[]byte)
		if ! {
			 = &[]byte{}
		}
		race.WriteSlice([:])
		defer estblockPool[].Put()

		 = calcBlockSize(, )
	}

	if  == 0 {
		return -1
	}
	// Size of the varint encoded block size.
	 += (bits.Len64(uint64(len())) + 7) / 7

	if  >= len() {
		return -1
	}
	return 
}

// EncodeBetter returns the encoded form of src. The returned slice may be a sub-
// slice of dst if dst was large enough to hold the entire encoded block.
// Otherwise, a newly allocated slice will be returned.
//
// EncodeBetter compresses better than Encode but typically with a
// 10-40% speed decrease on both compression and decompression.
//
// The dst and src must not overlap. It is valid to pass a nil dst.
//
// The blocks will require the same amount of memory to decode as encoding,
// and does not make for concurrent decoding.
// Also note that blocks do not contain CRC information, so corruption may be undetected.
//
// If you need to encode larger amounts of data, consider using
// the streaming interface which gives all of these features.
func (,  []byte) []byte {
	if  := MaxEncodedLen(len());  < 0 {
		panic(ErrTooLarge)
	} else if cap() <  {
		 = make([]byte, )
	} else {
		 = [:]
	}

	// The block starts with the varint-encoded length of the decompressed bytes.
	 := binary.PutUvarint(, uint64(len()))

	if len() == 0 {
		return [:]
	}
	if len() < minNonLiteralBlockSize {
		 += emitLiteral([:], )
		return [:]
	}
	 := encodeBlockBetter([:], )
	if  > 0 {
		 += 
		return [:]
	}
	// Not compressible
	 += emitLiteral([:], )
	return [:]
}

// EncodeBest returns the encoded form of src. The returned slice may be a sub-
// slice of dst if dst was large enough to hold the entire encoded block.
// Otherwise, a newly allocated slice will be returned.
//
// EncodeBest compresses as good as reasonably possible but with a
// big speed decrease.
//
// The dst and src must not overlap. It is valid to pass a nil dst.
//
// The blocks will require the same amount of memory to decode as encoding,
// and does not make for concurrent decoding.
// Also note that blocks do not contain CRC information, so corruption may be undetected.
//
// If you need to encode larger amounts of data, consider using
// the streaming interface which gives all of these features.
func (,  []byte) []byte {
	if  := MaxEncodedLen(len());  < 0 {
		panic(ErrTooLarge)
	} else if cap() <  {
		 = make([]byte, )
	} else {
		 = [:]
	}

	// The block starts with the varint-encoded length of the decompressed bytes.
	 := binary.PutUvarint(, uint64(len()))

	if len() == 0 {
		return [:]
	}
	if len() < minNonLiteralBlockSize {
		 += emitLiteral([:], )
		return [:]
	}
	 := encodeBlockBest([:], , nil)
	if  > 0 {
		 += 
		return [:]
	}
	// Not compressible
	 += emitLiteral([:], )
	return [:]
}

// EncodeSnappy returns the encoded form of src. The returned slice may be a sub-
// slice of dst if dst was large enough to hold the entire encoded block.
// Otherwise, a newly allocated slice will be returned.
//
// The output is Snappy compatible and will likely decompress faster.
//
// The dst and src must not overlap. It is valid to pass a nil dst.
//
// The blocks will require the same amount of memory to decode as encoding,
// and does not make for concurrent decoding.
// Also note that blocks do not contain CRC information, so corruption may be undetected.
//
// If you need to encode larger amounts of data, consider using
// the streaming interface which gives all of these features.
func (,  []byte) []byte {
	if  := MaxEncodedLen(len());  < 0 {
		panic(ErrTooLarge)
	} else if cap() <  {
		 = make([]byte, )
	} else {
		 = [:]
	}

	// The block starts with the varint-encoded length of the decompressed bytes.
	 := binary.PutUvarint(, uint64(len()))

	if len() == 0 {
		return [:]
	}
	if len() < minNonLiteralBlockSize {
		 += emitLiteral([:], )
		return [:]
	}

	 := encodeBlockSnappy([:], )
	if  > 0 {
		 += 
		return [:]
	}
	// Not compressible
	 += emitLiteral([:], )
	return [:]
}

// EncodeSnappyBetter returns the encoded form of src. The returned slice may be a sub-
// slice of dst if dst was large enough to hold the entire encoded block.
// Otherwise, a newly allocated slice will be returned.
//
// The output is Snappy compatible and will likely decompress faster.
//
// The dst and src must not overlap. It is valid to pass a nil dst.
//
// The blocks will require the same amount of memory to decode as encoding,
// and does not make for concurrent decoding.
// Also note that blocks do not contain CRC information, so corruption may be undetected.
//
// If you need to encode larger amounts of data, consider using
// the streaming interface which gives all of these features.
func (,  []byte) []byte {
	if  := MaxEncodedLen(len());  < 0 {
		panic(ErrTooLarge)
	} else if cap() <  {
		 = make([]byte, )
	} else {
		 = [:]
	}

	// The block starts with the varint-encoded length of the decompressed bytes.
	 := binary.PutUvarint(, uint64(len()))

	if len() == 0 {
		return [:]
	}
	if len() < minNonLiteralBlockSize {
		 += emitLiteral([:], )
		return [:]
	}

	 := encodeBlockBetterSnappy([:], )
	if  > 0 {
		 += 
		return [:]
	}
	// Not compressible
	 += emitLiteral([:], )
	return [:]
}

// EncodeSnappyBest returns the encoded form of src. The returned slice may be a sub-
// slice of dst if dst was large enough to hold the entire encoded block.
// Otherwise, a newly allocated slice will be returned.
//
// The output is Snappy compatible and will likely decompress faster.
//
// The dst and src must not overlap. It is valid to pass a nil dst.
//
// The blocks will require the same amount of memory to decode as encoding,
// and does not make for concurrent decoding.
// Also note that blocks do not contain CRC information, so corruption may be undetected.
//
// If you need to encode larger amounts of data, consider using
// the streaming interface which gives all of these features.
func (,  []byte) []byte {
	if  := MaxEncodedLen(len());  < 0 {
		panic(ErrTooLarge)
	} else if cap() <  {
		 = make([]byte, )
	} else {
		 = [:]
	}

	// The block starts with the varint-encoded length of the decompressed bytes.
	 := binary.PutUvarint(, uint64(len()))

	if len() == 0 {
		return [:]
	}
	if len() < minNonLiteralBlockSize {
		 += emitLiteral([:], )
		return [:]
	}

	 := encodeBlockBestSnappy([:], )
	if  > 0 {
		 += 
		return [:]
	}
	// Not compressible
	 += emitLiteral([:], )
	return [:]
}

// ConcatBlocks will concatenate the supplied blocks and append them to the supplied destination.
// If the destination is nil or too small, a new will be allocated.
// The blocks are not validated, so garbage in = garbage out.
// dst may not overlap block data.
// Any data in dst is preserved as is, so it will not be considered a block.
func ( []byte,  ...[]byte) ([]byte, error) {
	 := uint64(0)
	 := 0
	for ,  := range  {
		, ,  := decodedLen()
		if  != nil {
			return nil, 
		}
		 += uint64()
		 += len() - 
	}
	if  == 0 {
		 = append(, 0)
		return , nil
	}
	if  > math.MaxUint32 {
		return nil, ErrTooLarge
	}
	var  [binary.MaxVarintLen32]byte
	 := binary.PutUvarint([:], )
	 :=  + 

	if cap()-len() <  {
		 = append(make([]byte, 0, +len()), ...)
	}
	 = append(, [:]...)
	for ,  := range  {
		, ,  := decodedLen()
		if  != nil {
			return nil, 
		}
		 = append(, [:]...)
	}
	return , nil
}

// inputMargin is the minimum number of extra input bytes to keep, inside
// encodeBlock's inner loop. On some architectures, this margin lets us
// implement a fast path for emitLiteral, where the copy of short (<= 16 byte)
// literals can be implemented as a single load to and store from a 16-byte
// register. That literal's actual length can be as short as 1 byte, so this
// can copy up to 15 bytes too much, but that's OK as subsequent iterations of
// the encoding loop will fix up the copy overrun, and this inputMargin ensures
// that we don't overrun the dst and src buffers.
const inputMargin = 8

// minNonLiteralBlockSize is the minimum size of the input to encodeBlock that
// will be accepted by the encoder.
const minNonLiteralBlockSize = 32

const intReduction = 2 - (1 << (^uint(0) >> 63)) // 1 (32 bits) or 0 (64 bits)

// MaxBlockSize is the maximum value where MaxEncodedLen will return a valid block size.
// Blocks this big are highly discouraged, though.
// Half the size on 32 bit systems.
const MaxBlockSize = (1<<(32-intReduction) - 1) - binary.MaxVarintLen32 - 5

// MaxEncodedLen returns the maximum length of a snappy block, given its
// uncompressed length.
//
// It will return a negative value if srcLen is too large to encode.
// 32 bit platforms will have lower thresholds for rejecting big content.
func ( int) int {
	 := uint64()
	if intReduction == 1 {
		// 32 bits
		if  > math.MaxInt32 {
			// Also includes negative.
			return -1
		}
	} else if  > 0xffffffff {
		// 64 bits
		// Also includes negative.
		return -1
	}
	// Size of the varint encoded block size.
	 =  + uint64((bits.Len64()+7)/7)

	// Add maximum size of encoding block as literals.
	 += uint64(literalExtraSize(int64()))
	if intReduction == 1 {
		// 32 bits
		if  > math.MaxInt32 {
			return -1
		}
	} else if  > 0xffffffff {
		// 64 bits
		// Also includes negative.
		return -1
	}
	return int()
}