// Rank/select columns for the moderately-sparse band: O(1) reads without
// the binary search of a sparse column. present marks which positions carry
// a value; blockRank[b] caches the number of set bits before block b
// (rankBlock positions per block); values hold the values in ascending
// position order. Built by Finalize; serialized as sparse columns.

package chickpeas

import (
	

	
)

// rankBlock is the positions-per-block granularity. One word per block
// makes a Get exactly two loads plus one masked popcount -- no partial-sum
// loop -- at the cost of a block-rank array half the presence bitmap's
// size (in-memory only; rank columns serialize as sparse).
const rankBlock = 64

type rankIndex struct {
	present   *bitset.Bits
	blockRank []uint32
}

// slot returns the index into values for pos, or not-ok when pos carries no
// value. O(1): one blockRank read plus a bounded popcount.
func ( rankIndex) ( uint32) (int, bool) {
	 := int()
	if  >= .present.Len() || !.present.Get() {
		return 0, false
	}
	 :=  / rankBlock
	return int(.blockRank[]) + .present.CountRange(*rankBlock, ), true
}

func ( rankIndex) ( func( int) Value) iter.Seq2[uint32, Value] {
	return func( func(uint32, Value) bool) {
		 := 0
		for  := range .present.Ones() {
			if !(uint32(), ()) {
				return
			}
			++
		}
	}
}

// buildRankIndex builds the presence bitmap + block-rank index from
// position-sorted pairs over a span-position column space.
func buildRankIndex( []uint32,  int) rankIndex {
	 := bitset.New()
	for ,  := range  {
		.Set(int(), true)
	}
	 := ( + rankBlock - 1) / rankBlock
	 := make([]uint32, 0, +1)
	 = append(, 0)
	 := uint32(0)
	for  := range  {
		 += uint32(.CountRange(*rankBlock, min((+1)*rankBlock, )))
		 = append(, )
	}
	return rankIndex{present: , blockRank: }
}

type rankI64Col struct {
	rankIndex
	vals []int64
}

func ( rankI64Col) ( uint32) (Value, bool) {
	if ,  := .slot();  {
		return I64Value(.vals[]), true
	}
	return Value{}, false
}

func ( rankI64Col) () iter.Seq2[uint32, Value] {
	return .entries(func( int) Value { return I64Value(.vals[]) })
}

func ( rankI64Col) () Dtype { return DtypeI64 }
func ( rankI64Col) () int     { return len(.vals) }

type rankF64Col struct {
	rankIndex
	vals []float64
}

func ( rankF64Col) ( uint32) (Value, bool) {
	if ,  := .slot();  {
		return F64Value(.vals[]), true
	}
	return Value{}, false
}

func ( rankF64Col) () iter.Seq2[uint32, Value] {
	return .entries(func( int) Value { return F64Value(.vals[]) })
}

func ( rankF64Col) () Dtype { return DtypeF64 }
func ( rankF64Col) () int     { return len(.vals) }

type rankBoolCol struct {
	rankIndex
	vals *bitset.Bits
}

func ( rankBoolCol) ( uint32) (Value, bool) {
	if ,  := .slot();  {
		return BoolValue(.vals.Get()), true
	}
	return Value{}, false
}

func ( rankBoolCol) () iter.Seq2[uint32, Value] {
	return .entries(func( int) Value { return BoolValue(.vals.Get()) })
}

func ( rankBoolCol) () Dtype { return DtypeBool }
func ( rankBoolCol) () int     { return .vals.Len() }

type rankStrCol struct {
	rankIndex
	vals []uint32
}

func ( rankStrCol) ( uint32) (Value, bool) {
	if ,  := .slot();  {
		return StrValue(.vals[]), true
	}
	return Value{}, false
}

func ( rankStrCol) () iter.Seq2[uint32, Value] {
	return .entries(func( int) Value { return StrValue(.vals[]) })
}

func ( rankStrCol) () Dtype { return DtypeStr }
func ( rankStrCol) () int     { return len(.vals) }