// Typed column readers: the key -> column lookup is done once via// Snapshot.Col / Snapshot.RelCol, then narrowed to a typed reader -- the// polars column(name).i64() shape. Dense columns read through their raw// slice fast path; sparse columns binary-search, or read O(1) through a// lazily built position index (Snapshot.ColIndexed / RelColIndexed).package chickpeasimport ()// posIndex accelerates a sparse column's random reads: a presence bitmap// with block ranks resolves pos -> pair slot in O(1) -- one rank read plus// a bounded popcount, no hashing or per-probe branching. A sparse column's// pair array is position-sorted (its own Get binary-searches it), so the// rank IS the slot. nil means unindexed (dense and rank layouts are// already O(1)).type posIndex = *rankIndexfunc buildPosIndex( Column) posIndex { := make([]uint32, 0, .Len()) := 0for := range .Entries() { = append(, )ifint()+1 > { = int() + 1 } } := buildRankIndex(, )return &}// readIndexed reads a position through the resolved index when present,// else the column's own lookup.func readIndexed( Column, posIndex, uint32) (Value, bool) {if == nil {return .Get() } , := .slot()if ! {returnValue{}, false }returnvalueAtSlot(, uint32())}// Col is a resolved property column, narrowed to a typed reader with I64 /// F64 / Bool / Str. Build with Snapshot.Col (node columns, indexed by node// id) or Snapshot.RelCol (rel columns, indexed by outgoing-CSR position).typeColstruct { col Column idx posIndex}// Dtype is the column's logical element type, for picking a typed reader// without narrowing.func ( Col) () Dtype { return .col.Dtype() }// Column is the raw generic reader.func ( Col) () Column { return .col }// I64 narrows to a typed integer reader; a non-integer column reads back as// absent, like a mistyped Prop.func ( Col) () I64Col { := I64Col{col: .col, idx: .idx}switch d := .col.(type) {casedenseI64Col: .dense = casedenseI64NarrowCol: .nv = &i64NarrowView{narrow: .b, w: .w, min: .min}casedenseI64BitCol: .nv = &i64NarrowView{bits: .bits, min: .min} }return}// F64 narrows to a typed float reader.func ( Col) () F64Col { , := .col.(denseF64Col)returnF64Col{dense: , col: .col, idx: .idx}}// Bool narrows to a typed boolean reader.func ( Col) () BoolCol {var *bitset.Bitsif , := .col.(denseBoolCol); { = .bits }returnBoolCol{dense: , col: .col, idx: .idx}}// Str narrows to a typed string reader exposing interned atom ids; resolve// a comparison string to its atom once and compare ids.func ( Col) () StrCol { , := .col.(denseStrCol)returnStrCol{dense: , col: .col, idx: .idx}}// i64NarrowView is the unpacked read state for the narrow and bit// storage classes, held behind one pointer so I64Col itself stays small:// Get has a value receiver, so every field added to I64Col is copied on// every call -- unpacking these six words inline made each read pay a// duffcopy that cost more than the decode it saved (task 300).type i64NarrowView struct {// narrow is the byte-class delta vector (value = min + delta at // width w); bits is the two-valued bit class's vector (value = // min + bit). narrow []byte w uint8 min int64 bits *bitset.Bits}// I64Col is a resolved integer column reader.typeI64Colstruct { dense denseI64Col// nv is the narrow/bit-class read state (nil for other layouts), // one pointer so the value receiver stays cheap to copy. nv *i64NarrowView col Column idx posIndex}// Get returns the value at pos (a node id for node columns, a CSR position// for rel columns); ok is false when absent.func ( I64Col) ( uint32) (int64, bool) {if .dense != nil {ifint() < len(.dense) {return .dense[], true }return0, false }if .nv != nil {return .nv.get() } , := readIndexed(.col, .idx, )if ! {return0, false }return .I64()}// get decodes pos from the narrow byte classes; the bit class splits out// so this stays inlinable into Get -- the split plus the u48 single-load// keeps a narrow read one call level flatter than the fallback path. The// u48 arm bounds on i+8 against the 2-byte-padded buffer -- exact, since// a valid slot satisfies i <= len-8 and the first out-of-range slot lands// at i = len-2; narrower widths divide the unpadded length evenly.func ( *i64NarrowView) ( uint32) (int64, bool) {if .narrow == nil {return .getBits() } := int() * int(.w)switch .w {case1:if < len(.narrow) {return .min + int64(.narrow[]), true }case2:if +2 <= len(.narrow) {return .min + int64(binary.LittleEndian.Uint16(.narrow[:])), true }case4:if +4 <= len(.narrow) {return .min + int64(binary.LittleEndian.Uint32(.narrow[:])), true }default:if +8 <= len(.narrow) {return .min + int64(binary.LittleEndian.Uint64(.narrow[:])&narrowU48Mask), true } }return0, false}// getBits decodes pos from the two-valued bit class.func ( *i64NarrowView) ( uint32) (int64, bool) {ifint() >= .bits.Len() {return0, false }if .bits.Get(int()) {return .min + 1, true }return .min, true}// Slice is the dense value slice indexed directly by position; ok is false// for a sparse column (fall back to Get).func ( I64Col) () ([]int64, bool) {return .dense, .dense != nil}// GetMany reads the values at ids into vals with a presence mask -- the// bulk form of Get for candidate-batch sweeps: the representation switch// and the receiver hoist out of the loop, so a chunk pays one dispatch// instead of a call chain per id. vals and present must be at least// len(ids) long.func ( I64Col) ( []uint32, []int64, []bool) {switch {case .dense != nil: := .densefor , := range {ifint() < len() { [], [] = [], true } else { [] = false } }case .nv != nil && .nv.narrow != nil: , , := .nv, .nv.narrow, .nv.minswitch .w {case1:for , := range {ifint() < len() { [], [] = +int64([]), true } else { [] = false } }case2:for , := range {if := int() * 2; +2 <= len() { [], [] = +int64(binary.LittleEndian.Uint16([:])), true } else { [] = false } }case4:for , := range {if := int() * 4; +4 <= len() { [], [] = +int64(binary.LittleEndian.Uint32([:])), true } else { [] = false } }default:// u48: the buffer carries a 2-byte pad, so the padded 8-byte // masked load bounds exactly like Get's arm.for , := range {if := int() * 6; +8 <= len() { [], [] = +int64(binary.LittleEndian.Uint64([:])&narrowU48Mask), true } else { [] = false } } }default:for , := range { [], [] = .Get() } }}// SliceRange is the dense-speed window of a column whose presence is one// contiguous position run: values read as vals[pos-start], and a// position outside [start, start+len) is absent. LDBC-shaped loaders// assign each label a contiguous id block, so a label-scoped column// stored sparse still reads at hoisted-slice speed through its window// (the rcp twin's as_i64_slice_range, tasks rcp-265/072; a sparse// column's pair array is position-sorted, so contiguous presence makes// the value array itself the window -- the check is O(1) and nothing is// built). ok=false for gapped presence or a non-integer column.func ( I64Col) () ( uint32, []int64, bool) {if .dense != nil {return0, .dense, true } , := .col.(sparseI64Col) := len(.ids)if ! || == 0 || int(.ids[-1]-.ids[0])+1 != {return0, nil, false }return .ids[0], .vals, true}// F64Col is a resolved float column reader.typeF64Colstruct { dense denseF64Col col Column idx posIndex}// Get returns the value at pos; ok is false when absent.func ( F64Col) ( uint32) (float64, bool) {if .dense != nil {ifint() < len(.dense) {return .dense[], true }return0, false } , := readIndexed(.col, .idx, )if ! {return0, false }return .F64()}// Slice is the dense value slice; ok is false for a sparse column.func ( F64Col) () ([]float64, bool) {return .dense, .dense != nil}// SliceRange is I64Col.SliceRange for float columns.func ( F64Col) () ( uint32, []float64, bool) {if .dense != nil {return0, .dense, true } , := .col.(sparseF64Col) := len(.ids)if ! || == 0 || int(.ids[-1]-.ids[0])+1 != {return0, nil, false }return .ids[0], .vals, true}// BoolCol is a resolved boolean column reader.typeBoolColstruct { dense *bitset.Bits col Column idx posIndex}// Get returns the value at pos; ok is false when absent.func ( BoolCol) ( uint32) (bool, bool) {if .dense != nil {ifint() < .dense.Len() {return .dense.Get(int()), true }returnfalse, false } , := readIndexed(.col, .idx, )if ! {returnfalse, false }return .Bool()}// Bits is the dense bit vector indexed directly by position; ok is false// for a sparse column.func ( BoolCol) () (*bitset.Bits, bool) {return .dense, .dense != nil}// StrCol is a resolved string column reader exposing interned atom ids.typeStrColstruct { dense denseStrCol col Column idx posIndex}// ID returns the atom id at pos; ok is false when absent. Note atom 0 ("")// in a dense column means missing -- Prop.Str folds that in; this raw// reader does not.func ( StrCol) ( uint32) (uint32, bool) {if .dense != nil {ifint() < len(.dense) {return .dense[], true }return0, false } , := readIndexed(.col, .idx, )if ! {return0, false }return .StrID()}// IDs is the dense atom-id slice; ok is false for a sparse column.func ( StrCol) () ([]uint32, bool) {return .dense, .dense != nil}
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.