// This file gets added on all the little-endian CPU architectures.

//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh || wasm

package parquet

import (
	
	
	
	
)

type ColumnIndex interface {
	// NumPages returns the number of paged in the column index.
	NumPages() int

	// Returns the number of null values in the page at the given index.
	NullCount(int) int64

	// Tells whether the page at the given index contains null values only.
	NullPage(int) bool

	// PageIndex return min/max bounds for the page at the given index in the
	// column.
	MinValue(int) Value
	MaxValue(int) Value

	// IsAscending returns true if the column index min/max values are sorted
	// in ascending order (based on the ordering rules of the column's logical
	// type).
	IsAscending() bool

	// IsDescending returns true if the column index min/max values are sorted
	// in descending order (based on the ordering rules of the column's logical
	// type).
	IsDescending() bool
}

// NewColumnIndex constructs a ColumnIndex instance from the given parquet
// format column index. The kind argument configures the type of values
func ( Kind,  *format.ColumnIndex) ColumnIndex {
	return &formatColumnIndex{
		kind:  ,
		index: ,
	}
}

type formatColumnIndex struct {
	kind  Kind
	index *format.ColumnIndex
}

func ( *formatColumnIndex) () int {
	return len(.index.MinValues)
}

func ( *formatColumnIndex) ( int) int64 {
	if len(.index.NullCounts) > 0 {
		return .index.NullCounts[]
	}
	return 0
}

func ( *formatColumnIndex) ( int) bool {
	return len(.index.NullPages) > 0 && .index.NullPages[]
}

func ( *formatColumnIndex) ( int) Value {
	if .NullPage() {
		return Value{}
	}
	return .kind.Value(.index.MinValues[])
}

func ( *formatColumnIndex) ( int) Value {
	if .NullPage() {
		return Value{}
	}
	return .kind.Value(.index.MaxValues[])
}

func ( *formatColumnIndex) () bool {
	return .index.BoundaryOrder == format.Ascending
}

func ( *formatColumnIndex) () bool {
	return .index.BoundaryOrder == format.Descending
}

type fileColumnIndex struct{ chunk *fileColumnChunk }

func ( fileColumnIndex) () int {
	return len(.columnIndex().NullPages)
}

func ( fileColumnIndex) ( int) int64 {
	 := .columnIndex()
	if len(.NullCounts) > 0 {
		return .NullCounts[]
	}
	return 0
}

func ( fileColumnIndex) ( int) bool {
	return isNullPage(, .columnIndex())
}

func ( fileColumnIndex) ( int) Value {
	 := .columnIndex()
	if isNullPage(, ) {
		return Value{}
	}
	return .makeValue(.MinValues[])
}

func ( fileColumnIndex) ( int) Value {
	 := .columnIndex()
	if isNullPage(, ) {
		return Value{}
	}
	return .makeValue(.MaxValues[])
}

func ( fileColumnIndex) () bool {
	return .columnIndex().BoundaryOrder == format.Ascending
}

func ( fileColumnIndex) () bool {
	return .columnIndex().BoundaryOrder == format.Descending
}

func ( *fileColumnIndex) ( []byte) Value {
	return .chunk.column.typ.Kind().Value()
}

func ( fileColumnIndex) () *format.ColumnIndex { return .chunk.columnIndex.Load() }

func isNullPage( int,  *format.ColumnIndex) bool {
	return len(.NullPages) > 0 && .NullPages[]
}

type emptyColumnIndex struct{}

func (emptyColumnIndex) () int       { return 0 }
func (emptyColumnIndex) (int) int64 { return 0 }
func (emptyColumnIndex) (int) bool   { return false }
func (emptyColumnIndex) (int) Value  { return Value{} }
func (emptyColumnIndex) (int) Value  { return Value{} }
func (emptyColumnIndex) () bool   { return false }
func (emptyColumnIndex) () bool  { return false }

type booleanColumnIndex struct{ page *booleanPage }

func ( booleanColumnIndex) () int       { return 1 }
func ( booleanColumnIndex) (int) int64 { return 0 }
func ( booleanColumnIndex) (int) bool   { return false }
func ( booleanColumnIndex) (int) Value  { return makeValueBoolean(.page.min()) }
func ( booleanColumnIndex) (int) Value  { return makeValueBoolean(.page.max()) }
func ( booleanColumnIndex) () bool   { return false }
func ( booleanColumnIndex) () bool  { return false }

type int32ColumnIndex struct{ page *int32Page }

func ( int32ColumnIndex) () int       { return 1 }
func ( int32ColumnIndex) (int) int64 { return 0 }
func ( int32ColumnIndex) (int) bool   { return false }
func ( int32ColumnIndex) (int) Value  { return makeValueInt32(.page.min()) }
func ( int32ColumnIndex) (int) Value  { return makeValueInt32(.page.max()) }
func ( int32ColumnIndex) () bool   { return false }
func ( int32ColumnIndex) () bool  { return false }

type int64ColumnIndex struct{ page *int64Page }

func ( int64ColumnIndex) () int       { return 1 }
func ( int64ColumnIndex) (int) int64 { return 0 }
func ( int64ColumnIndex) (int) bool   { return false }
func ( int64ColumnIndex) (int) Value  { return makeValueInt64(.page.min()) }
func ( int64ColumnIndex) (int) Value  { return makeValueInt64(.page.max()) }
func ( int64ColumnIndex) () bool   { return false }
func ( int64ColumnIndex) () bool  { return false }

type int96ColumnIndex struct{ page *int96Page }

func ( int96ColumnIndex) () int       { return 1 }
func ( int96ColumnIndex) (int) int64 { return 0 }
func ( int96ColumnIndex) (int) bool   { return false }
func ( int96ColumnIndex) (int) Value  { return makeValueInt96(.page.min()) }
func ( int96ColumnIndex) (int) Value  { return makeValueInt96(.page.max()) }
func ( int96ColumnIndex) () bool   { return false }
func ( int96ColumnIndex) () bool  { return false }

type floatColumnIndex struct{ page *floatPage }

func ( floatColumnIndex) () int       { return 1 }
func ( floatColumnIndex) (int) int64 { return 0 }
func ( floatColumnIndex) (int) bool   { return false }
func ( floatColumnIndex) (int) Value  { return makeValueFloat(.page.min()) }
func ( floatColumnIndex) (int) Value  { return makeValueFloat(.page.max()) }
func ( floatColumnIndex) () bool   { return false }
func ( floatColumnIndex) () bool  { return false }

type doubleColumnIndex struct{ page *doublePage }

func ( doubleColumnIndex) () int       { return 1 }
func ( doubleColumnIndex) (int) int64 { return 0 }
func ( doubleColumnIndex) (int) bool   { return false }
func ( doubleColumnIndex) (int) Value  { return makeValueDouble(.page.min()) }
func ( doubleColumnIndex) (int) Value  { return makeValueDouble(.page.max()) }
func ( doubleColumnIndex) () bool   { return false }
func ( doubleColumnIndex) () bool  { return false }

type byteArrayColumnIndex struct{ page *byteArrayPage }

func ( byteArrayColumnIndex) () int       { return 1 }
func ( byteArrayColumnIndex) (int) int64 { return 0 }
func ( byteArrayColumnIndex) (int) bool   { return false }
func ( byteArrayColumnIndex) (int) Value  { return makeValueBytes(ByteArray, .page.min()) }
func ( byteArrayColumnIndex) (int) Value  { return makeValueBytes(ByteArray, .page.max()) }
func ( byteArrayColumnIndex) () bool   { return false }
func ( byteArrayColumnIndex) () bool  { return false }

type fixedLenByteArrayColumnIndex struct{ page *fixedLenByteArrayPage }

func ( fixedLenByteArrayColumnIndex) () int       { return 1 }
func ( fixedLenByteArrayColumnIndex) (int) int64 { return 0 }
func ( fixedLenByteArrayColumnIndex) (int) bool   { return false }
func ( fixedLenByteArrayColumnIndex) (int) Value {
	return makeValueBytes(FixedLenByteArray, .page.min())
}
func ( fixedLenByteArrayColumnIndex) (int) Value {
	return makeValueBytes(FixedLenByteArray, .page.max())
}
func ( fixedLenByteArrayColumnIndex) () bool  { return false }
func ( fixedLenByteArrayColumnIndex) () bool { return false }

type uint32ColumnIndex struct{ page *uint32Page }

func ( uint32ColumnIndex) () int       { return 1 }
func ( uint32ColumnIndex) (int) int64 { return 0 }
func ( uint32ColumnIndex) (int) bool   { return false }
func ( uint32ColumnIndex) (int) Value  { return makeValueUint32(.page.min()) }
func ( uint32ColumnIndex) (int) Value  { return makeValueUint32(.page.max()) }
func ( uint32ColumnIndex) () bool   { return false }
func ( uint32ColumnIndex) () bool  { return false }

type uint64ColumnIndex struct{ page *uint64Page }

func ( uint64ColumnIndex) () int       { return 1 }
func ( uint64ColumnIndex) (int) int64 { return 0 }
func ( uint64ColumnIndex) (int) bool   { return false }
func ( uint64ColumnIndex) (int) Value  { return makeValueUint64(.page.min()) }
func ( uint64ColumnIndex) (int) Value  { return makeValueUint64(.page.max()) }
func ( uint64ColumnIndex) () bool   { return false }
func ( uint64ColumnIndex) () bool  { return false }

type be128ColumnIndex struct{ page *be128Page }

func ( be128ColumnIndex) () int       { return 1 }
func ( be128ColumnIndex) (int) int64 { return 0 }
func ( be128ColumnIndex) (int) bool   { return false }
func ( be128ColumnIndex) (int) Value  { return makeValueBytes(FixedLenByteArray, .page.min()) }
func ( be128ColumnIndex) (int) Value  { return makeValueBytes(FixedLenByteArray, .page.max()) }
func ( be128ColumnIndex) () bool   { return false }
func ( be128ColumnIndex) () bool  { return false }

// The ColumnIndexer interface is implemented by types that support generating
// parquet column indexes.
//
// The package does not export any types that implement this interface, programs
// must call NewColumnIndexer on a Type instance to construct column indexers.
type ColumnIndexer interface {
	// Resets the column indexer state.
	Reset()

	// Add a page to the column indexer.
	IndexPage(numValues, numNulls int64, min, max Value)

	// Generates a format.ColumnIndex value from the current state of the
	// column indexer.
	//
	// The returned value may reference internal buffers, in which case the
	// values remain valid until the next call to IndexPage or Reset on the
	// column indexer.
	ColumnIndex() format.ColumnIndex
}

type baseColumnIndexer struct {
	nullPages  []bool
	nullCounts []int64
}

func ( *baseColumnIndexer) () {
	.nullPages = .nullPages[:0]
	.nullCounts = .nullCounts[:0]
}

func ( *baseColumnIndexer) (,  int64) {
	.nullPages = append(.nullPages,  == )
	.nullCounts = append(.nullCounts, )
}

func ( *baseColumnIndexer) (,  [][]byte, ,  int) format.ColumnIndex {
	 := make([]bool, len(.nullPages))
	copy(, .nullPages)
	 := make([]int64, len(.nullCounts))
	copy(, .nullCounts)
	return format.ColumnIndex{
		NullPages:     ,
		NullCounts:    ,
		MinValues:     ,
		MaxValues:     ,
		BoundaryOrder: boundaryOrderOf(, ),
	}
}

type booleanColumnIndexer struct {
	baseColumnIndexer
	minValues []bool
	maxValues []bool
}

func newBooleanColumnIndexer() *booleanColumnIndexer {
	return new(booleanColumnIndexer)
}

func ( *booleanColumnIndexer) () {
	.reset()
	.minValues = .minValues[:0]
	.maxValues = .maxValues[:0]
}

func ( *booleanColumnIndexer) (,  int64, ,  Value) {
	.observe(, )
	.minValues = append(.minValues, .boolean())
	.maxValues = append(.maxValues, .boolean())
}

func ( *booleanColumnIndexer) () format.ColumnIndex {
	return .columnIndex(
		splitFixedLenByteArrays(unsafecast.Slice[byte](.minValues), 1),
		splitFixedLenByteArrays(unsafecast.Slice[byte](.maxValues), 1),
		orderOfBool(.minValues),
		orderOfBool(.maxValues),
	)
}

type int32ColumnIndexer struct {
	baseColumnIndexer
	minValues []int32
	maxValues []int32
}

func newInt32ColumnIndexer() *int32ColumnIndexer {
	return new(int32ColumnIndexer)
}

func ( *int32ColumnIndexer) () {
	.reset()
	.minValues = .minValues[:0]
	.maxValues = .maxValues[:0]
}

func ( *int32ColumnIndexer) (,  int64, ,  Value) {
	.observe(, )
	.minValues = append(.minValues, .int32())
	.maxValues = append(.maxValues, .int32())
}

func ( *int32ColumnIndexer) () format.ColumnIndex {
	return .columnIndex(
		splitFixedLenByteArrays(unsafecast.Slice[byte](.minValues), 4),
		splitFixedLenByteArrays(unsafecast.Slice[byte](.maxValues), 4),
		orderOfInt32(.minValues),
		orderOfInt32(.maxValues),
	)
}

type int64ColumnIndexer struct {
	baseColumnIndexer
	minValues []int64
	maxValues []int64
}

func newInt64ColumnIndexer() *int64ColumnIndexer {
	return new(int64ColumnIndexer)
}

func ( *int64ColumnIndexer) () {
	.reset()
	.minValues = .minValues[:0]
	.maxValues = .maxValues[:0]
}

func ( *int64ColumnIndexer) (,  int64, ,  Value) {
	.observe(, )
	.minValues = append(.minValues, .int64())
	.maxValues = append(.maxValues, .int64())
}

func ( *int64ColumnIndexer) () format.ColumnIndex {
	return .columnIndex(
		splitFixedLenByteArrays(unsafecast.Slice[byte](.minValues), 8),
		splitFixedLenByteArrays(unsafecast.Slice[byte](.maxValues), 8),
		orderOfInt64(.minValues),
		orderOfInt64(.maxValues),
	)
}

type int96ColumnIndexer struct {
	baseColumnIndexer
	minValues []deprecated.Int96
	maxValues []deprecated.Int96
}

func newInt96ColumnIndexer() *int96ColumnIndexer {
	return new(int96ColumnIndexer)
}

func ( *int96ColumnIndexer) () {
	.reset()
	.minValues = .minValues[:0]
	.maxValues = .maxValues[:0]
}

func ( *int96ColumnIndexer) (,  int64, ,  Value) {
	.observe(, )
	.minValues = append(.minValues, .Int96())
	.maxValues = append(.maxValues, .Int96())
}

func ( *int96ColumnIndexer) () format.ColumnIndex {
	return .columnIndex(
		splitFixedLenByteArrays(unsafecast.Slice[byte](.minValues), 12),
		splitFixedLenByteArrays(unsafecast.Slice[byte](.maxValues), 12),
		deprecated.OrderOfInt96(.minValues),
		deprecated.OrderOfInt96(.maxValues),
	)
}

type floatColumnIndexer struct {
	baseColumnIndexer
	minValues []float32
	maxValues []float32
}

func newFloatColumnIndexer() *floatColumnIndexer {
	return new(floatColumnIndexer)
}

func ( *floatColumnIndexer) () {
	.reset()
	.minValues = .minValues[:0]
	.maxValues = .maxValues[:0]
}

func ( *floatColumnIndexer) (,  int64, ,  Value) {
	.observe(, )
	.minValues = append(.minValues, .float())
	.maxValues = append(.maxValues, .float())
}

func ( *floatColumnIndexer) () format.ColumnIndex {
	return .columnIndex(
		splitFixedLenByteArrays(unsafecast.Slice[byte](.minValues), 4),
		splitFixedLenByteArrays(unsafecast.Slice[byte](.maxValues), 4),
		orderOfFloat32(.minValues),
		orderOfFloat32(.maxValues),
	)
}

type doubleColumnIndexer struct {
	baseColumnIndexer
	minValues []float64
	maxValues []float64
}

func newDoubleColumnIndexer() *doubleColumnIndexer {
	return new(doubleColumnIndexer)
}

func ( *doubleColumnIndexer) () {
	.reset()
	.minValues = .minValues[:0]
	.maxValues = .maxValues[:0]
}

func ( *doubleColumnIndexer) (,  int64, ,  Value) {
	.observe(, )
	.minValues = append(.minValues, .double())
	.maxValues = append(.maxValues, .double())
}

func ( *doubleColumnIndexer) () format.ColumnIndex {
	return .columnIndex(
		splitFixedLenByteArrays(unsafecast.Slice[byte](.minValues), 8),
		splitFixedLenByteArrays(unsafecast.Slice[byte](.maxValues), 8),
		orderOfFloat64(.minValues),
		orderOfFloat64(.maxValues),
	)
}

type byteArrayColumnIndexer struct {
	baseColumnIndexer
	sizeLimit int
	minValues []byte
	maxValues []byte
}

func newByteArrayColumnIndexer( int) *byteArrayColumnIndexer {
	return &byteArrayColumnIndexer{sizeLimit: }
}

func ( *byteArrayColumnIndexer) () {
	.reset()
	.minValues = .minValues[:0]
	.maxValues = .maxValues[:0]
}

func ( *byteArrayColumnIndexer) (,  int64, ,  Value) {
	.observe(, )
	.minValues = plain.AppendByteArray(.minValues, .byteArray())
	.maxValues = plain.AppendByteArray(.maxValues, .byteArray())
}

func ( *byteArrayColumnIndexer) () format.ColumnIndex {
	 := splitByteArrays(.minValues)
	 := splitByteArrays(.maxValues)
	if  := .sizeLimit;  > 0 {
		for ,  := range  {
			[] = truncateLargeMinByteArrayValue(, )
		}
		for ,  := range  {
			[] = truncateLargeMaxByteArrayValue(, )
		}
	}
	return .columnIndex(
		,
		,
		orderOfBytes(),
		orderOfBytes(),
	)
}

type fixedLenByteArrayColumnIndexer struct {
	baseColumnIndexer
	size      int
	sizeLimit int
	minValues []byte
	maxValues []byte
}

func newFixedLenByteArrayColumnIndexer(,  int) *fixedLenByteArrayColumnIndexer {
	return &fixedLenByteArrayColumnIndexer{
		size:      ,
		sizeLimit: ,
	}
}

func ( *fixedLenByteArrayColumnIndexer) () {
	.reset()
	.minValues = .minValues[:0]
	.maxValues = .maxValues[:0]
}

func ( *fixedLenByteArrayColumnIndexer) (,  int64, ,  Value) {
	.observe(, )
	.minValues = append(.minValues, .byteArray()...)
	.maxValues = append(.maxValues, .byteArray()...)
}

func ( *fixedLenByteArrayColumnIndexer) () format.ColumnIndex {
	 := splitFixedLenByteArrays(.minValues, .size)
	 := splitFixedLenByteArrays(.maxValues, .size)
	if  := .sizeLimit;  > 0 {
		for ,  := range  {
			[] = truncateLargeMinByteArrayValue(, )
		}
		for ,  := range  {
			[] = truncateLargeMaxByteArrayValue(, )
		}
	}
	return .columnIndex(
		,
		,
		orderOfBytes(),
		orderOfBytes(),
	)
}

type uint32ColumnIndexer struct {
	baseColumnIndexer
	minValues []uint32
	maxValues []uint32
}

func newUint32ColumnIndexer() *uint32ColumnIndexer {
	return new(uint32ColumnIndexer)
}

func ( *uint32ColumnIndexer) () {
	.reset()
	.minValues = .minValues[:0]
	.maxValues = .maxValues[:0]
}

func ( *uint32ColumnIndexer) (,  int64, ,  Value) {
	.observe(, )
	.minValues = append(.minValues, .uint32())
	.maxValues = append(.maxValues, .uint32())
}

func ( *uint32ColumnIndexer) () format.ColumnIndex {
	return .columnIndex(
		splitFixedLenByteArrays(unsafecast.Slice[byte](.minValues), 4),
		splitFixedLenByteArrays(unsafecast.Slice[byte](.maxValues), 4),
		orderOfUint32(.minValues),
		orderOfUint32(.maxValues),
	)
}

type uint64ColumnIndexer struct {
	baseColumnIndexer
	minValues []uint64
	maxValues []uint64
}

func newUint64ColumnIndexer() *uint64ColumnIndexer {
	return new(uint64ColumnIndexer)
}

func ( *uint64ColumnIndexer) () {
	.reset()
	.minValues = .minValues[:0]
	.maxValues = .maxValues[:0]
}

func ( *uint64ColumnIndexer) (,  int64, ,  Value) {
	.observe(, )
	.minValues = append(.minValues, .uint64())
	.maxValues = append(.maxValues, .uint64())
}

func ( *uint64ColumnIndexer) () format.ColumnIndex {
	return .columnIndex(
		splitFixedLenByteArrays(unsafecast.Slice[byte](.minValues), 8),
		splitFixedLenByteArrays(unsafecast.Slice[byte](.maxValues), 8),
		orderOfUint64(.minValues),
		orderOfUint64(.maxValues),
	)
}

type be128ColumnIndexer struct {
	baseColumnIndexer
	minValues [][16]byte
	maxValues [][16]byte
}

func newBE128ColumnIndexer() *be128ColumnIndexer {
	return new(be128ColumnIndexer)
}

func ( *be128ColumnIndexer) () {
	.reset()
	.minValues = .minValues[:0]
	.maxValues = .maxValues[:0]
}

func ( *be128ColumnIndexer) (,  int64, ,  Value) {
	.observe(, )
	if !.IsNull() {
		.minValues = append(.minValues, *(*[16]byte)(.byteArray()))
	}
	if !.IsNull() {
		.maxValues = append(.maxValues, *(*[16]byte)(.byteArray()))
	}
}

func ( *be128ColumnIndexer) () format.ColumnIndex {
	 := splitFixedLenByteArrays(unsafecast.Slice[byte](.minValues), 16)
	 := splitFixedLenByteArrays(unsafecast.Slice[byte](.maxValues), 16)
	return .columnIndex(
		,
		,
		orderOfBytes(),
		orderOfBytes(),
	)
}

func truncateLargeMinByteArrayValue( []byte,  int) []byte {
	if len() >  {
		 = [:]
	}
	return 
}

// truncateLargeMaxByteArrayValue truncates the given byte array to the given size limit.
// If the given byte array is truncated, it is incremented by 1 in place.
func truncateLargeMaxByteArrayValue( []byte,  int) []byte {
	if len() >  {
		 = [:]
		incrementByteArrayInplace()
	}
	return 
}

// incrementByteArray increments the given byte array by 1.
// Reference: https://github.com/apache/parquet-java/blob/master/parquet-column/src/main/java/org/apache/parquet/internal/column/columnindex/BinaryTruncator.java#L124
func incrementByteArrayInplace( []byte) {
	for  := len() - 1;  >= 0; -- {
		[]++
		if [] != 0 { // Did not overflow: 0xFF -> 0x00
			return
		}
	}
	// Fully overflowed, so restore all to 0xFF
	for  := range  {
		[] = 0xFF
	}
}

func splitByteArrays( []byte) [][]byte {
	 := 0
	plain.RangeByteArray(, func([]byte) error {
		++
		return nil
	})
	 := make([]byte, 0, len()-(4*))
	 := make([][]byte, 0, )
	plain.RangeByteArray(, func( []byte) error {
		 := len()
		 = append(, ...)
		 = append(, [:])
		return nil
	})
	return 
}

func splitFixedLenByteArrays( []byte,  int) [][]byte {
	 = copyBytes()
	 := make([][]byte, len()/)
	for  := range  {
		 := ( + 0) * 
		 := ( + 1) * 
		[] = [::]
	}
	return 
}

func boundaryOrderOf(,  int) format.BoundaryOrder {
	if  ==  {
		switch {
		case  > 0:
			return format.Ascending
		case  < 0:
			return format.Descending
		}
	}
	return format.Unordered
}