// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build go1.18

package kernels

import (
	
	

	
	
	
	
	
	
	
)

// scalar kernel that ignores (assumed all-null inputs) and returns null
func ( *exec.KernelCtx,  *exec.ExecSpan,  *exec.ExecResult) error {
	return nil
}

func ( int) exec.ScalarKernel {
	 := make([]exec.InputType, )
	for  := range  {
		[] = exec.NewIDInput(arrow.NULL)
	}
	return exec.NewScalarKernel(, exec.NewOutputType(arrow.Null), NullToNullExec, nil)
}

func ( ArithmeticOp) []exec.ScalarKernel {
	 := (time.Hour * 24)
	return []exec.ScalarKernel{exec.NewScalarKernel([]exec.InputType{
		exec.NewExactInput(arrow.FixedWidthTypes.Time32s),
		exec.NewExactInput(&arrow.DurationType{Unit: arrow.Second})}, OutputFirstType,
		timeDurationOp[arrow.Time32, arrow.Time32, arrow.Duration](int64(.Seconds()), ), nil),
		exec.NewScalarKernel([]exec.InputType{
			exec.NewExactInput(arrow.FixedWidthTypes.Time32ms),
			exec.NewExactInput(&arrow.DurationType{Unit: arrow.Millisecond})}, OutputFirstType,
			timeDurationOp[arrow.Time32, arrow.Time32, arrow.Duration](int64(.Milliseconds()), ), nil),
		exec.NewScalarKernel([]exec.InputType{
			exec.NewExactInput(arrow.FixedWidthTypes.Time64us),
			exec.NewExactInput(&arrow.DurationType{Unit: arrow.Microsecond})}, OutputFirstType,
			timeDurationOp[arrow.Time64, arrow.Time64, arrow.Duration](int64(.Microseconds()), ), nil),
		exec.NewScalarKernel([]exec.InputType{
			exec.NewExactInput(arrow.FixedWidthTypes.Time64ns),
			exec.NewExactInput(&arrow.DurationType{Unit: arrow.Nanosecond})}, OutputFirstType,
			timeDurationOp[arrow.Time64, arrow.Time64, arrow.Duration](int64(.Nanoseconds()), ), nil)}
}

func ( ArithmeticOp) []exec.ScalarKernel {
	var  exec.OutputType
	switch  {
	case OpAdd, OpSub, OpAddChecked, OpSubChecked:
		 = exec.NewComputedOutputType(resolveDecimalAddOrSubtractType)
	case OpMul, OpMulChecked:
		 = exec.NewComputedOutputType(resolveDecimalMultiplyOutput)
	case OpDiv, OpDivChecked:
		 = exec.NewComputedOutputType(resolveDecimalDivideOutput)
	}

	,  := exec.NewIDInput(arrow.DECIMAL128), exec.NewIDInput(arrow.DECIMAL256)
	,  := getArithmeticDecimal[decimal128.Num](), getArithmeticDecimal[decimal256.Num]()
	return []exec.ScalarKernel{
		exec.NewScalarKernel([]exec.InputType{, }, , , nil),
		exec.NewScalarKernel([]exec.InputType{, }, , , nil),
	}
}

func ( ArithmeticOp) []exec.ScalarKernel {
	 := make([]exec.ScalarKernel, 0)
	for ,  := range numericTypes {
		 = append(, exec.NewScalarKernel(
			[]exec.InputType{exec.NewExactInput(), exec.NewExactInput()},
			exec.NewOutputType(), ArithmeticExecSameType(.ID(), ), nil))
	}

	return append(, NullExecKernel(2))
}

func ( ArithmeticOp) []exec.ScalarKernel {
	 := OutputFirstType
	 := exec.NewIDInput(arrow.DECIMAL128)
	 := exec.NewIDInput(arrow.DECIMAL256)

	,  := getArithmeticDecimal[decimal128.Num](), getArithmeticDecimal[decimal256.Num]()
	return []exec.ScalarKernel{
		exec.NewScalarKernel([]exec.InputType{}, , , nil),
		exec.NewScalarKernel([]exec.InputType{}, , , nil),
	}
}

func ( ArithmeticOp) []exec.ScalarKernel {
	 := make([]exec.ScalarKernel, 0)
	for ,  := range numericTypes {
		 = append(, exec.NewScalarKernel(
			[]exec.InputType{exec.NewExactInput()}, exec.NewOutputType(),
			ArithmeticExec(.ID(), .ID(), ), nil))
	}

	return append(, NullExecKernel(1))
}

func ( ArithmeticOp) []exec.ScalarKernel {
	 := make([]exec.ScalarKernel, 0)
	for ,  := range append(signedIntTypes, floatingTypes...) {
		 = append(, exec.NewScalarKernel(
			[]exec.InputType{exec.NewExactInput()}, exec.NewOutputType(),
			ArithmeticExec(.ID(), .ID(), ), nil))
	}

	return append(, NullExecKernel(1))
}

func ( ArithmeticOp) []exec.ScalarKernel {
	 := make([]exec.ScalarKernel, 0)
	for ,  := range floatingTypes {
		 = append(, exec.NewScalarKernel(
			[]exec.InputType{exec.NewExactInput()}, exec.NewOutputType(),
			ArithmeticExec(.ID(), .ID(), ), nil))
	}

	return append(, NullExecKernel(1))
}

func ( ArithmeticOp) []exec.ScalarKernel {
	 := make([]exec.ScalarKernel, 0)
	for ,  := range floatingTypes {
		 := exec.NewExactInput()
		 = append(, exec.NewScalarKernel(
			[]exec.InputType{, }, exec.NewOutputType(),
			ArithmeticExecSameType(.ID(), ), nil))
	}

	return append(, NullExecKernel(2))
}

func ( arrow.DataType,  ArithmeticOp) []exec.ScalarKernel {
	 := make([]exec.ScalarKernel, 0)

	 := exec.NewOutputType()
	for ,  := range numericTypes {
		 := 
		 := 
		if arrow.IsFloating(.ID()) {
			 = 
			 = exec.NewOutputType()
		}

		 = append(, exec.NewScalarKernel(
			[]exec.InputType{exec.NewExactInput()}, ,
			ArithmeticExec(.ID(), .ID(), ), nil))
	}

	 = append(, exec.NewScalarKernel(
		[]exec.InputType{exec.NewIDInput(arrow.DECIMAL128)},
		exec.NewOutputType(arrow.PrimitiveTypes.Int64),
		getArithmeticDecimal[decimal128.Num](), nil))
	 = append(, exec.NewScalarKernel(
		[]exec.InputType{exec.NewIDInput(arrow.DECIMAL256)},
		exec.NewOutputType(arrow.PrimitiveTypes.Int64),
		getArithmeticDecimal[decimal256.Num](), nil))

	return append(, NullExecKernel(1))
}

type BitwiseOp int8

const (
	OpBitAnd BitwiseOp = iota
	OpBitOr
	OpBitXor
)

func bitwiseKernelOp( BitwiseOp) exec.ArrayKernelExec {
	var  func([]byte, []byte, int64, int64, []byte, int64, int64)
	switch  {
	case OpBitOr:
		 = bitutil.BitmapOr
	case OpBitAnd:
		 = bitutil.BitmapAnd
	case OpBitXor:
		 = bitutil.BitmapXor
	}

	 := func(,  *exec.ArraySpan,  *exec.ExecResult) error {
		 := int64(.Type.(arrow.FixedWidthDataType).BitWidth())
		(.Buffers[1].Buf, .Buffers[1].Buf,
			*.Offset, *.Offset,
			.Buffers[1].Buf, *.Offset, *.Len)
		return nil
	}

	 := func( *exec.ArraySpan,  scalar.Scalar,  *exec.ExecResult) error {
		if !.IsValid() {
			// no work to be done, everything is null
			return nil
		}

		 := .(scalar.PrimitiveScalar).Data()
		 := int64(len())
		 :=  * 8
		 := .Buffers[1].Buf[*.Offset:]
		 := .Buffers[1].Buf[*.Offset:]

		for  := int64(0);  < .Len; ++ {
			(, , 0, 0, , 0, )
			,  = [:], [:]
		}
		return nil
	}

	return func( *exec.KernelCtx,  *exec.ExecSpan,  *exec.ExecResult) error {
		if .Values[0].IsArray() {
			if .Values[1].IsArray() {
				return (&.Values[0].Array, &.Values[1].Array, )
			}
			return (&.Values[0].Array, .Values[1].Scalar, )
		}

		if .Values[1].IsArray() {
			return (&.Values[1].Array, .Values[0].Scalar, )
		}

		debug.Assert(false, "should be unreachable")
		return fmt.Errorf("%w: scalar binary with two scalars?", arrow.ErrInvalid)
	}
}

func ( BitwiseOp) []exec.ScalarKernel {
	 := make([]exec.ScalarKernel, 0)
	for ,  := range intTypes {
		 := bitwiseKernelOp()
		 := exec.NewExactInput()
		 = append(, exec.NewScalarKernel([]exec.InputType{
			, }, exec.NewOutputType(), , nil))
	}
	return append(, NullExecKernel(2))
}

func bitwiseNot[ arrow.IntType | arrow.UintType]( *exec.KernelCtx,  ,  *error)  {
	return ^
}

func getBitwiseNotExec( arrow.DataType) exec.ArrayKernelExec {
	switch .ID() {
	case arrow.INT8, arrow.UINT8:
		return ScalarUnaryNotNull(bitwiseNot[uint8])
	case arrow.INT16, arrow.UINT16:
		return ScalarUnaryNotNull(bitwiseNot[uint16])
	case arrow.INT32, arrow.UINT32:
		return ScalarUnaryNotNull(bitwiseNot[uint32])
	case arrow.INT64, arrow.UINT64:
		return ScalarUnaryNotNull(bitwiseNot[uint64])
	}
	panic("only integral types for bitwise not kernels")
}

func () []exec.ScalarKernel {
	 := make([]exec.ScalarKernel, 0)
	for ,  := range intTypes {
		 := getBitwiseNotExec()
		 = append(, exec.NewScalarKernel(
			[]exec.InputType{exec.NewExactInput()}, exec.NewOutputType(),
			, nil))
	}
	return append(, NullExecKernel(1))
}

type ShiftDir int8

const (
	ShiftLeft ShiftDir = iota
	ShiftRight
)

func shiftKernelSignedImpl[ arrow.IntType,  arrow.UintType]( ShiftDir,  bool) exec.ArrayKernelExec {
	 := fmt.Errorf("%w: shift amount must be >= 0 and less than precision of type", arrow.ErrInvalid)
	 := (8*SizeOf[]() - 1)

	switch  {
	case ShiftLeft:
		if  {
			return ScalarBinaryNotNull(func( *exec.KernelCtx, ,  ,  *error)  {
				if  < 0 ||  >=  {
					* = 
					return 
				}
				return (() << ())
			})
		}

		return ScalarBinaryNotNull(func( *exec.KernelCtx, ,  ,  *error)  {
			if  < 0 ||  >=  {
				return 
			}

			return (() << ())
		})
	case ShiftRight:
		if  {
			return ScalarBinaryNotNull(func( *exec.KernelCtx, ,  ,  *error)  {
				if  < 0 ||  >=  {
					* = 
					return 
				}
				return  >> 
			})
		}

		return ScalarBinaryNotNull(func( *exec.KernelCtx, ,  ,  *error)  {
			if  < 0 ||  >=  {
				return 
			}
			return  >> 
		})
	}
	return nil
}

func shiftKernelUnsignedImpl[ arrow.UintType]( ShiftDir,  bool) exec.ArrayKernelExec {
	 := fmt.Errorf("%w: shift amount must be >= 0 and less than precision of type", arrow.ErrInvalid)
	 := (8 * SizeOf[]())

	switch  {
	case ShiftLeft:
		if  {
			return ScalarBinaryNotNull(func( *exec.KernelCtx, ,  ,  *error)  {
				if  < 0 ||  >=  {
					* = 
					return 
				}
				return  << 
			})
		}

		return ScalarBinaryNotNull(func( *exec.KernelCtx, ,  ,  *error)  {
			if  < 0 ||  >=  {
				return 
			}
			return  << 
		})
	case ShiftRight:
		if  {
			return ScalarBinaryNotNull(func( *exec.KernelCtx, ,  ,  *error)  {
				if  < 0 ||  >=  {
					* = 
					return 
				}
				return  >> 
			})
		}

		return ScalarBinaryNotNull(func( *exec.KernelCtx, ,  ,  *error)  {
			if  < 0 ||  >=  {
				return 
			}
			return  >> 
		})
	}
	return nil
}

func shiftKernel( ShiftDir,  bool,  arrow.Type) exec.ArrayKernelExec {
	switch  {
	case arrow.INT8:
		return shiftKernelSignedImpl[int8, uint8](, )
	case arrow.UINT8:
		return shiftKernelUnsignedImpl[uint8](, )
	case arrow.INT16:
		return shiftKernelSignedImpl[int16, uint16](, )
	case arrow.UINT16:
		return shiftKernelUnsignedImpl[uint16](, )
	case arrow.INT32:
		return shiftKernelSignedImpl[int32, uint32](, )
	case arrow.UINT32:
		return shiftKernelUnsignedImpl[uint32](, )
	case arrow.INT64:
		return shiftKernelSignedImpl[int64, uint64](, )
	case arrow.UINT64:
		return shiftKernelUnsignedImpl[uint64](, )
	}
	panic("invalid type for shift kernels")
}

func ( ShiftDir,  bool) []exec.ScalarKernel {
	 := make([]exec.ScalarKernel, 0)
	for ,  := range intTypes {
		 := exec.NewExactInput()
		 := shiftKernel(, , .ID())
		 = append(, exec.NewScalarKernel(
			[]exec.InputType{, }, exec.NewOutputType(),
			, nil))
	}
	return append(, NullExecKernel(2))
}