package builder

import (
	
	
	
	
	

	
	
	
	
	
)

// ColumnBuilder is a subset of the array.Builder interface implemented by the
// optimized builders in this file.
type ColumnBuilder interface {
	Retain()
	Release()
	Len() int
	AppendNull()
	Reserve(int)
	NewArray() arrow.Array
}

// OptimizedBuilder is a set of FrostDB specific builder methods.
type OptimizedBuilder interface {
	ColumnBuilder
	AppendNulls(int)
	ResetToLength(int)
	RepeatLastValue(int) error
	IsNull(i int) bool
	IsValid(i int) bool
	SetNull(i int)
}

type builderBase struct {
	dtype          arrow.DataType
	refCount       int64
	length         int
	validityBitmap []byte
}

func ( *builderBase) () {
	.length = 0
	.validityBitmap = .validityBitmap[:0]
}

func ( *builderBase) () {
	atomic.AddInt64(&.refCount, 1)
}

func ( *builderBase) () {
	.length = 0
	.validityBitmap = nil
}

func ( *builderBase) () {
	atomic.AddInt64(&.refCount, -1)
	.releaseInternal()
}

// Len returns the number of elements in the array builder.
func ( *builderBase) () int {
	return .length
}

func ( *builderBase) (int) {}

// AppendNulls appends n null values to the array being built. This is specific
// to distinct optimizations in FrostDB.
func ( *builderBase) ( int) {
	.validityBitmap = resizeBitmap(.validityBitmap, .length+)
	bitutil.SetBitsTo(.validityBitmap, int64(.length), int64(), false)
	.length += 
}

// SetNull is setting the value at the index i to null.
func ( *builderBase) ( int) {
	bitutil.ClearBit(.validityBitmap, )
}

func ( *builderBase) ( int) bool {
	return bitutil.BitIsSet(.validityBitmap, )
}

// appendValid does the opposite of appendNulls.
func ( *builderBase) ( int) {
	.validityBitmap = resizeBitmap(.validityBitmap, .length+)
	bitutil.SetBitsTo(.validityBitmap, int64(.length), int64(), true)
	.length += 
}

func ( *builderBase) ( int) bool {
	return bitutil.BitIsNotSet(.validityBitmap, )
}

func resizeBitmap( []byte,  int) []byte {
	 := int(bitutil.BytesForBits(int64()))
	if cap() <  {
		 := 
		 = make([]byte, bitutil.NextPowerOf2())
		copy(, )
	}
	return [:]
}

var (
	_ OptimizedBuilder = (*OptBinaryBuilder)(nil)
	_ OptimizedBuilder = (*OptInt64Builder)(nil)
	_ OptimizedBuilder = (*OptBooleanBuilder)(nil)
	_ OptimizedBuilder = (*OptFloat64Builder)(nil)
)

// OptBinaryBuilder is an optimized array.BinaryBuilder.
type OptBinaryBuilder struct {
	builderBase

	data []byte
	// offsets are offsets into data. The ith value is
	// data[offsets[i]:offsets[i+1]]. Note however, that during normal operation,
	// len(data) is never appended to the slice until the next value is added,
	// i.e. the last offset is never closed until the offsets slice is appended
	// to or returned to the caller.
	offsets []uint32
}

func ( arrow.BinaryDataType) *OptBinaryBuilder {
	 := &OptBinaryBuilder{}
	.dtype = 
	return 
}

// Release decreases the reference count by 1.
// When the reference count goes to zero, the memory is freed.
// Release may be called simultaneously from multiple goroutines.
func ( *OptBinaryBuilder) () {
	if atomic.AddInt64(&.refCount, -1) == 0 {
		.data = nil
		.offsets = nil
		.releaseInternal()
	}
}

// AppendNull adds a new null value to the array being built. This is slow,
// don't use it.
func ( *OptBinaryBuilder) () {
	.offsets = append(.offsets, uint32(len(.data)))
	.builderBase.AppendNulls(1)
}

// AppendEmptyValue adds a new empty byte slice to the array being built.
func ( *OptBinaryBuilder) () {
	.offsets = append(.offsets, uint32(len(.data)))
	// Don't append any data, just close the offset for an empty slice
	.appendValid(1)
}

// AppendNulls appends n null values to the array being built. This is specific
// to distinct optimizations in FrostDB.
func ( *OptBinaryBuilder) ( int) {
	for  := 0;  < ; ++ {
		.offsets = append(.offsets, uint32(len(.data)))
	}
	.builderBase.AppendNulls()
}

// NewArray creates a new array from the memory buffers used
// by the builder and resets the Builder so it can be used to build
// a new array.
func ( *OptBinaryBuilder) () arrow.Array {
	.offsets = append(.offsets, uint32(len(.data)))
	 := unsafe.Slice((*byte)(unsafe.Pointer(unsafe.SliceData(.offsets))), len(.offsets)*arrow.Uint32SizeBytes)
	 := array.NewData(
		.dtype,
		.length,
		[]*memory.Buffer{
			memory.NewBufferBytes(.validityBitmap),
			memory.NewBufferBytes(),
			memory.NewBufferBytes(.data),
		},
		nil,
		.length-bitutil.CountSetBits(.validityBitmap, 0, .length),
		0,
	)
	.reset()
	.offsets = .offsets[:0]
	.data = nil

	return array.NewBinaryData()
}

var ErrMaxSizeReached = fmt.Errorf("max size reached")

// AppendData appends a flat slice of bytes to the builder, with an accompanying
// slice of offsets. This data is considered to be non-null.
func ( *OptBinaryBuilder) ( []byte,  []uint32) error {
	if len(.data)+len() > math.MaxInt32 { // NOTE: we check against a max int32 here (instead of the uint32 that we're using for offsets) because the arror binary arrays use int32s.
		return ErrMaxSizeReached
	}

	// Trim the last offset since we want this last range to be "open".
	 = [:len()-1]

	 := uint32(len(.data))
	.data = append(.data, ...)
	 := len(.offsets)
	.offsets = append(.offsets, ...)
	for  := ;  < len(.offsets); ++ {
		.offsets[] += 
	}

	.length += len()
	.validityBitmap = resizeBitmap(.validityBitmap, .length)
	bitutil.SetBitsTo(.validityBitmap, int64(), int64(len()), true)
	return nil
}

func ( *OptBinaryBuilder) ( []byte) error {
	if len(.data)+len() > math.MaxInt32 {
		return ErrMaxSizeReached
	}
	.offsets = append(.offsets, uint32(len(.data)))
	.data = append(.data, ...)
	.length++
	.validityBitmap = resizeBitmap(.validityBitmap, .length)
	bitutil.SetBit(.validityBitmap, .length-1)
	return nil
}

// AppendParquetValues appends the given parquet values to the builder. The
// values may be null, but if it is known upfront that none of the values are
// null, AppendData offers a more efficient way of appending values.
func ( *OptBinaryBuilder) ( []parquet.Value) error {
	 := 0
	for  := range  {
		 += len([].ByteArray())
	}
	if len(.data)+ > math.MaxInt32 {
		return ErrMaxSizeReached
	}

	for  := range  {
		.offsets = append(.offsets, uint32(len(.data)))
		.data = append(.data, [].ByteArray()...)
	}

	 := .length
	.length += len()

	.validityBitmap = resizeBitmap(.validityBitmap, .length)
	for  := range  {
		bitutil.SetBitTo(.validityBitmap, +, ![].IsNull())
	}

	return nil
}

// RepeatLastValue is specific to distinct optimizations in FrostDB.
func ( *OptBinaryBuilder) ( int) error {
	if bitutil.BitIsNotSet(.validityBitmap, .length-1) {
		// Last value is null.
		.AppendNulls()
		return nil
	}

	 := .data[.offsets[len(.offsets)-1]:]
	if len(.data)+(len()*) > math.MaxInt32 {
		return ErrMaxSizeReached
	}
	for  := 0;  < ; ++ {
		.offsets = append(.offsets, uint32(len(.data)))
		.data = append(.data, ...)
	}
	.appendValid()
	return nil
}

// ResetToLength is specific to distinct optimizations in FrostDB.
func ( *OptBinaryBuilder) ( int) {
	if  == .length {
		return
	}

	.length = 
	.data = .data[:.offsets[]]
	.offsets = .offsets[:]
	.validityBitmap = resizeBitmap(.validityBitmap, )
}

func ( *OptBinaryBuilder) ( int) []byte {
	if  == .length-1 { // last value
		return .data[.offsets[]:]
	}
	return .data[.offsets[]:.offsets[+1]]
}

type OptInt64Builder struct {
	builderBase

	data []int64
}

func ( arrow.DataType) *OptInt64Builder {
	 := &OptInt64Builder{}
	.dtype = 
	return 
}

func ( *OptInt64Builder) ( int) {
	if cap(.data) <  {
		 := .data
		.data = make([]int64, bitutil.NextPowerOf2())
		copy(.data, )
	}
	.data = .data[:]
}

func ( *OptInt64Builder) () {
	if atomic.AddInt64(&.refCount, -1) == 0 {
		.data = nil
		.releaseInternal()
	}
}

func ( *OptInt64Builder) () {
	.AppendNulls(1)
}

// AppendEmptyValue adds a new zero value (0) to the array being built.
func ( *OptInt64Builder) () {
	.Append(0)
}

func ( *OptInt64Builder) ( int) {
	.resizeData(.length + )
	.builderBase.AppendNulls()
}

func ( *OptInt64Builder) () arrow.Array {
	 := unsafe.Slice((*byte)(unsafe.Pointer(unsafe.SliceData(.data))), len(.data)*arrow.Int64SizeBytes)
	 := array.NewData(
		.dtype,
		.length,
		[]*memory.Buffer{
			memory.NewBufferBytes(.validityBitmap),
			memory.NewBufferBytes(),
		},
		nil,
		.length-bitutil.CountSetBits(.validityBitmap, 0, .length),
		0,
	)
	.reset()
	.data = nil
	return array.NewInt64Data()
}

// AppendData appends a slice of int64s to the builder. This data is considered
// to be non-null.
func ( *OptInt64Builder) ( []int64) {
	 := .length
	.data = append(.data, ...)
	.length += len()
	.validityBitmap = resizeBitmap(.validityBitmap, .length)
	bitutil.SetBitsTo(.validityBitmap, int64(), int64(len()), true)
}

func ( *OptInt64Builder) ( int64) {
	.data = append(.data, )
	.length++
	.validityBitmap = resizeBitmap(.validityBitmap, .length)
	bitutil.SetBit(.validityBitmap, .length-1)
}

func ( *OptInt64Builder) ( int,  int64) {
	.data[] = 
}

func ( *OptInt64Builder) ( int,  int64) {
	.data[] += 
}

// Value returns the ith value of the builder.
func ( *OptInt64Builder) ( int) int64 {
	return .data[]
}

func ( *OptInt64Builder) ( []parquet.Value) {
	.resizeData(.length + len())
	.validityBitmap = resizeBitmap(.validityBitmap, .length+len())
	for ,  := .length, 0;  < .length+len() &&  < len(); {
		.data[] = [].Int64()
		bitutil.SetBitTo(.validityBitmap, , ![].IsNull())
		++
		++
	}
	.length += len()
}

func ( *OptInt64Builder) ( int) error {
	if bitutil.BitIsNotSet(.validityBitmap, .length-1) {
		.AppendNulls()
		return nil
	}

	 := .data[.length-1]
	.resizeData(.length + )
	for  := .length;  < .length+; ++ {
		.data[] = 
	}
	.appendValid()
	return nil
}

// ResetToLength is specific to distinct optimizations in FrostDB.
func ( *OptInt64Builder) ( int) {
	if  == .length {
		return
	}

	.length = 
	.data = .data[:]
	.validityBitmap = resizeBitmap(.validityBitmap, )
}

type OptBooleanBuilder struct {
	builderBase
	data []byte
}

func ( arrow.DataType) *OptBooleanBuilder {
	 := &OptBooleanBuilder{}
	.dtype = 
	return 
}

func ( *OptBooleanBuilder) () {
	if atomic.AddInt64(&.refCount, -1) == 0 {
		.data = nil
		.releaseInternal()
	}
}

func ( *OptBooleanBuilder) () {
	.AppendNulls(1)
}

// AppendEmptyValue adds a new zero value (false) to the array being built.
func ( *OptBooleanBuilder) () {
	.AppendSingle(false)
}

func ( *OptBooleanBuilder) ( int) {
	 := .length + 
	.data = resizeBitmap(.data, )
	.validityBitmap = resizeBitmap(.validityBitmap, )

	for  := 0;  < ; ++ {
		bitutil.SetBitTo(.data, .length, false)
		bitutil.SetBitTo(.validityBitmap, .length, false)
		.length++
	}
}

func ( *OptBooleanBuilder) () arrow.Array {
	 := array.NewData(
		.dtype,
		.length,
		[]*memory.Buffer{
			memory.NewBufferBytes(.validityBitmap),
			memory.NewBufferBytes(.data),
		},
		nil,
		.length-bitutil.CountSetBits(.validityBitmap, 0, .length),
		0,
	)
	.reset()
	.data = nil
	 := array.NewBooleanData()
	return 
}

func ( *OptBooleanBuilder) ( []byte,  int) {
	 := .length + 
	.data = resizeBitmap(.data, )
	.validityBitmap = resizeBitmap(.validityBitmap, )

	// TODO: This isn't ideal setting bits 1 by 1, when we could copy in all the bits
	for  := 0;  < ; ++ {
		bitutil.SetBitTo(.data, .length, bitutil.BitIsSet(, ))
		bitutil.SetBitTo(.validityBitmap, .length, true)
		.length++
	}
}

func ( *OptBooleanBuilder) ( int,  bool) {
	bitutil.SetBitTo(.data, , )
}

func ( *OptBooleanBuilder) ( int) bool {
	return bitutil.BitIsSet(.data, )
}

func ( *OptBooleanBuilder) ( []byte) {
	panic("do not use AppendData for opt boolean builder, use Append instead")
}

func ( *OptBooleanBuilder) ( []parquet.Value) {
	 := .length + len()
	.data = resizeBitmap(.data, )
	.validityBitmap = resizeBitmap(.validityBitmap, )

	for ,  := range  {
		bitutil.SetBitTo(.data, .length, .Boolean())
		bitutil.SetBitTo(.validityBitmap, .length, true)
		.length++
	}
}

func ( *OptBooleanBuilder) ( bool) {
	.length++
	.data = resizeBitmap(.data, .length)
	.validityBitmap = resizeBitmap(.validityBitmap, .length)
	bitutil.SetBitTo(.data, .length-1, )
	bitutil.SetBit(.validityBitmap, .length-1)
}

func ( *OptBooleanBuilder) ( int) error {
	if bitutil.BitIsNotSet(.validityBitmap, .length-1) {
		.AppendNulls()
		return nil
	}

	 := bitutil.BitIsSet(.data, .length-1)
	.data = resizeBitmap(.data, .length+)
	bitutil.SetBitsTo(.data, int64(.length), int64(), )
	.appendValid()
	return nil
}

// ResetToLength is specific to distinct optimizations in FrostDB.
func ( *OptBooleanBuilder) ( int) {
	if  == .length {
		return
	}

	.length = 
	.data = resizeBitmap(.data, )
	.validityBitmap = resizeBitmap(.validityBitmap, )
}

type OptInt32Builder struct {
	builderBase

	data []int32
}

func ( arrow.DataType) *OptInt32Builder {
	 := &OptInt32Builder{}
	.dtype = 
	return 
}

func ( *OptInt32Builder) ( int) {
	if cap(.data) <  {
		 := .data
		.data = make([]int32, bitutil.NextPowerOf2())
		copy(.data, )
	}
	.data = .data[:]
}

func ( *OptInt32Builder) () {
	if atomic.AddInt64(&.refCount, -1) == 0 {
		.data = nil
		.releaseInternal()
	}
}

func ( *OptInt32Builder) () {
	.AppendNulls(1)
}

// AppendEmptyValue adds a new zero value (0) to the array being built.
func ( *OptInt32Builder) () {
	.Append(0)
}

func ( *OptInt32Builder) ( int) {
	.resizeData(.length + )
	.builderBase.AppendNulls()
}

func ( *OptInt32Builder) () arrow.Array {
	 := unsafe.Slice((*byte)(unsafe.Pointer(unsafe.SliceData(.data))), len(.data)*arrow.Int32SizeBytes)
	 := array.NewData(
		.dtype,
		.length,
		[]*memory.Buffer{
			memory.NewBufferBytes(.validityBitmap),
			memory.NewBufferBytes(),
		},
		nil,
		.length-bitutil.CountSetBits(.validityBitmap, 0, .length),
		0,
	)
	.reset()
	.data = nil
	return array.NewInt32Data()
}

// AppendData appends a slice of int32s to the builder. This data is considered
// to be non-null.
func ( *OptInt32Builder) ( []int32) {
	 := .length
	.data = append(.data, ...)
	.length += len()
	.validityBitmap = resizeBitmap(.validityBitmap, .length)
	bitutil.SetBitsTo(.validityBitmap, int64(), int64(len()), true)
}

func ( *OptInt32Builder) ( int32) {
	.data = append(.data, )
	.length++
	.validityBitmap = resizeBitmap(.validityBitmap, .length)
	bitutil.SetBit(.validityBitmap, .length-1)
}

// Set sets value v at index i. THis will panic if i is out of bounds. Use this
// after calling Reserve.
func ( *OptInt32Builder) ( int,  int32) {
	.data[] = 
	bitutil.SetBit(.validityBitmap, )
}

// Swap swaps values at i and j index.
func ( *OptInt32Builder) (,  int) {
	.data[], .data[] = .data[], .data[]
}

func ( *OptInt32Builder) ( int,  int32) {
	.data[] += 
}

func ( *OptInt32Builder) ( int) int32 {
	return .data[]
}

func ( *OptInt32Builder) ( []parquet.Value) {
	.resizeData(.length + len())
	.validityBitmap = resizeBitmap(.validityBitmap, .length+len())
	for ,  := .length, 0;  < .length+len() &&  < len(); {
		.data[] = [].Int32()
		bitutil.SetBitTo(.validityBitmap, , ![].IsNull())
		++
		++
	}
	.length += len()
}

func ( *OptInt32Builder) ( int) error {
	if bitutil.BitIsNotSet(.validityBitmap, .length-1) {
		.AppendNulls()
		return nil
	}

	 := .data[.length-1]
	.resizeData(.length + )
	for  := .length;  < .length+; ++ {
		.data[] = 
	}
	.appendValid()
	return nil
}

// ResetToLength is specific to distinct optimizations in FrostDB.
func ( *OptInt32Builder) ( int) {
	if  == .length {
		return
	}

	.length = 
	.data = .data[:]
	.validityBitmap = resizeBitmap(.validityBitmap, )
}

func ( *OptInt32Builder) ( int) {
	.length = 
	.data = slices.Grow(.data, )[:]
	.validityBitmap = resizeBitmap(.validityBitmap, )
}

type OptFloat64Builder struct {
	builderBase

	data []float64
}

func ( arrow.DataType) *OptFloat64Builder {
	 := &OptFloat64Builder{}
	.dtype = 
	return 
}

func ( *OptFloat64Builder) ( int) {
	if cap(.data) <  {
		 := .data
		.data = make([]float64, bitutil.NextPowerOf2())
		copy(.data, )
	}
	.data = .data[:]
}

func ( *OptFloat64Builder) () {
	if atomic.AddInt64(&.refCount, -1) == 0 {
		.data = nil
		.releaseInternal()
	}
}

func ( *OptFloat64Builder) () {
	.AppendNulls(1)
}

// AppendEmptyValue adds a new zero value (0.0) to the array being built.
func ( *OptFloat64Builder) () {
	.Append(0.0)
}

func ( *OptFloat64Builder) ( int) {
	.resizeData(.length + )
	.builderBase.AppendNulls()
}

func ( *OptFloat64Builder) () arrow.Array {
	 := unsafe.Slice((*byte)(unsafe.Pointer(unsafe.SliceData(.data))), len(.data)*arrow.Float64SizeBytes)
	 := array.NewData(
		.dtype,
		.length,
		[]*memory.Buffer{
			memory.NewBufferBytes(.validityBitmap),
			memory.NewBufferBytes(),
		},
		nil,
		.length-bitutil.CountSetBits(.validityBitmap, 0, .length),
		0,
	)
	.reset()
	.data = nil
	return array.NewFloat64Data()
}

// AppendData appends a slice of float64s to the builder.
// This data is considered to be non-null.
func ( *OptFloat64Builder) ( []float64) {
	 := .length
	.data = append(.data, ...)
	.length += len()
	.validityBitmap = resizeBitmap(.validityBitmap, .length)
	bitutil.SetBitsTo(.validityBitmap, int64(), int64(len()), true)
}

func ( *OptFloat64Builder) ( float64) {
	.data = append(.data, )
	.length++
	.validityBitmap = resizeBitmap(.validityBitmap, .length)
	bitutil.SetBit(.validityBitmap, .length-1)
}

func ( *OptFloat64Builder) ( int,  float64) {
	.data[] = 
}

func ( *OptFloat64Builder) ( int,  float64) {
	.data[] += 
}

// Value returns the ith value of the builder.
func ( *OptFloat64Builder) ( int) float64 {
	return .data[]
}

func ( *OptFloat64Builder) ( []parquet.Value) {
	.resizeData(.length + len())
	.validityBitmap = resizeBitmap(.validityBitmap, .length+len())
	for ,  := .length, 0;  < .length+len() &&  < len(); {
		.data[] = [].Double()
		bitutil.SetBitTo(.validityBitmap, , ![].IsNull())
		++
		++
	}
	.length += len()
}

func ( *OptFloat64Builder) ( int) error {
	if bitutil.BitIsNotSet(.validityBitmap, .length-1) {
		.AppendNulls()
		return nil
	}

	 := .data[.length-1]
	.resizeData(.length + )
	for  := .length;  < .length+; ++ {
		.data[] = 
	}
	.appendValid()
	return nil
}

// ResetToLength is specific to distinct optimizations in FrostDB.
func ( *OptFloat64Builder) ( int) {
	if  == .length {
		return
	}

	.length = 
	.data = .data[:]
	.validityBitmap = resizeBitmap(.validityBitmap, )
}