//go:build !purego

package delta

import (
	
	
)

func init() {
	if cpu.X86.HasAVX2 {
		encodeInt32 = encodeInt32AVX2
		encodeInt64 = encodeInt64AVX2
	}
}

//go:noescape
func blockDeltaInt32AVX2( *[blockSize]int32,  int32) int32

//go:noescape
func blockMinInt32AVX2( *[blockSize]int32) int32

//go:noescape
func blockSubInt32AVX2( *[blockSize]int32,  int32)

//go:noescape
func blockBitWidthsInt32AVX2( *[numMiniBlocks]byte,  *[blockSize]int32)

//go:noescape
func encodeMiniBlockInt32Default( *byte,  *[miniBlockSize]int32,  uint)

//go:noescape
func encodeMiniBlockInt32x1bitAVX2( *byte,  *[miniBlockSize]int32)

//go:noescape
func encodeMiniBlockInt32x2bitsAVX2( *byte,  *[miniBlockSize]int32)

//go:noescape
func encodeMiniBlockInt32x3to16bitsAVX2( *byte,  *[miniBlockSize]int32,  uint)

//go:noescape
func encodeMiniBlockInt32x32bitsAVX2( *byte,  *[miniBlockSize]int32)

func encodeMiniBlockInt32( []byte,  *[miniBlockSize]int32,  uint) {
	encodeMiniBlockInt32Default(&[0], , )
}

func encodeMiniBlockInt32AVX2( *byte,  *[miniBlockSize]int32,  uint) {
	switch {
	case  == 1:
		encodeMiniBlockInt32x1bitAVX2(, )
	case  == 2:
		encodeMiniBlockInt32x2bitsAVX2(, )
	case  == 32:
		encodeMiniBlockInt32x32bitsAVX2(, )
	case  <= 16:
		encodeMiniBlockInt32x3to16bitsAVX2(, , )
	default:
		encodeMiniBlockInt32Default(, , )
	}
}

func encodeInt32AVX2( []byte,  []int32) []byte {
	 := len()
	 := int32(0)
	if  > 0 {
		 = [0]
	}

	 := len()
	 = resize(, +maxHeaderLength32)
	 = [:+encodeBinaryPackedHeader([:], blockSize, numMiniBlocks, , int64())]

	if  < 2 {
		return 
	}

	 := 
	for  := 1;  < len();  += blockSize {
		 := [blockSize]int32{}
		 := copy([:], [:])

		 = blockDeltaInt32AVX2(&, )
		 := blockMinInt32AVX2(&)
		blockSubInt32AVX2(&, )
		blockClearInt32(&, )

		 := [numMiniBlocks]byte{}
		blockBitWidthsInt32AVX2(&, &)

		 := len()
		 = resize(, +maxMiniBlockLength32+16)
		 += encodeBlockHeader([:], int64(), )

		for ,  := range  {
			if  != 0 {
				 := (*[miniBlockSize]int32)([*miniBlockSize:])
				encodeMiniBlockInt32AVX2(&[], , uint())
				 += (miniBlockSize * int()) / 8
			}
		}

		 = [:]
	}

	return 
}

//go:noescape
func blockDeltaInt64AVX2( *[blockSize]int64,  int64) int64

//go:noescape
func blockMinInt64AVX2( *[blockSize]int64) int64

//go:noescape
func blockSubInt64AVX2( *[blockSize]int64,  int64)

//go:noescape
func blockBitWidthsInt64AVX2( *[numMiniBlocks]byte,  *[blockSize]int64)

//go:noescape
func encodeMiniBlockInt64Default( *byte,  *[miniBlockSize]int64,  uint)

//go:noescape
func encodeMiniBlockInt64x1bitAVX2( *byte,  *[miniBlockSize]int64)

//go:noescape
func encodeMiniBlockInt64x2bitsAVX2( *byte,  *[miniBlockSize]int64)

//go:noescape
func encodeMiniBlockInt64x64bitsAVX2( *byte,  *[miniBlockSize]int64)

func encodeMiniBlockInt64( []byte,  *[miniBlockSize]int64,  uint) {
	encodeMiniBlockInt64Default(&[0], , )
}

func encodeMiniBlockInt64AVX2( *byte,  *[miniBlockSize]int64,  uint) {
	switch {
	case  == 1:
		encodeMiniBlockInt64x1bitAVX2(, )
	case  == 2:
		encodeMiniBlockInt64x2bitsAVX2(, )
	case  == 64:
		encodeMiniBlockInt64x64bitsAVX2(, )
	default:
		encodeMiniBlockInt64Default(, , )
	}
}

func encodeInt64AVX2( []byte,  []int64) []byte {
	 := len()
	 := int64(0)
	if  > 0 {
		 = [0]
	}

	 := len()
	 = resize(, +maxHeaderLength64)
	 = [:+encodeBinaryPackedHeader([:], blockSize, numMiniBlocks, , int64())]

	if  < 2 {
		return 
	}

	 := 
	for  := 1;  < len();  += blockSize {
		 := [blockSize]int64{}
		 := copy([:], [:])

		 = blockDeltaInt64AVX2(&, )
		 := blockMinInt64AVX2(&)
		blockSubInt64AVX2(&, )
		blockClearInt64(&, )

		 := [numMiniBlocks]byte{}
		blockBitWidthsInt64AVX2(&, &)

		 := len()
		 = resize(, +maxMiniBlockLength64+16)
		 += encodeBlockHeader([:], int64(), )

		for ,  := range  {
			if  != 0 {
				 := (*[miniBlockSize]int64)([*miniBlockSize:])
				encodeMiniBlockInt64AVX2(&[], , uint())
				 += (miniBlockSize * int()) / 8
			}
		}

		 = [:]
	}

	return 
}

//go:noescape
func decodeBlockInt32Default( []int32, ,  int32) int32

//go:noescape
func decodeBlockInt32AVX2( []int32, ,  int32) int32

func decodeBlockInt32( []int32, ,  int32) int32 {
	switch {
	case cpu.X86.HasAVX2:
		return decodeBlockInt32AVX2(, , )
	default:
		return decodeBlockInt32Default(, , )
	}
}

//go:noescape
func decodeMiniBlockInt32Default( []int32,  []uint32,  uint)

//go:noescape
func decodeMiniBlockInt32x1to16bitsAVX2( []int32,  []uint32,  uint)

//go:noescape
func decodeMiniBlockInt32x17to26bitsAVX2( []int32,  []uint32,  uint)

//go:noescape
func decodeMiniBlockInt32x27to31bitsAVX2( []int32,  []uint32,  uint)

func decodeMiniBlockInt32( []int32,  []uint32,  uint) {
	 := cpu.X86.HasAVX2
	switch {
	case  &&  <= 16:
		decodeMiniBlockInt32x1to16bitsAVX2(, , )
	case  &&  <= 26:
		decodeMiniBlockInt32x17to26bitsAVX2(, , )
	case  &&  <= 31:
		decodeMiniBlockInt32x27to31bitsAVX2(, , )
	case  == 32:
		copy(, unsafecast.Slice[int32]())
	default:
		decodeMiniBlockInt32Default(, , )
	}
}

//go:noescape
func decodeBlockInt64Default( []int64, ,  int64) int64

func decodeBlockInt64( []int64, ,  int64) int64 {
	return decodeBlockInt64Default(, , )
}

//go:noescape
func decodeMiniBlockInt64Default( []int64,  []uint32,  uint)

func decodeMiniBlockInt64( []int64,  []uint32,  uint) {
	switch {
	case  == 64:
		copy(, unsafecast.Slice[int64]())
	default:
		decodeMiniBlockInt64Default(, , )
	}
}