// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com) // All rights reserved. // Bitmap filter RTL — Rushmore-style query optimization. // FoxPro Rushmore technology for Five. // // Usage: // BM_DbSetFilter({|| CITY = "Seoul"}) // create bitmap filter // BM_DbSeekWild("Park*") // wildcard seek // BM_Turbo(.T.) // enable turbo mode // BM_DbGetFilterArray() // get bitmap as array // BM_DbSetFilterArray(aBitmap) // set bitmap from array package hbrtl import ( "five/hbrt" "five/hbrdd" "strings" ) // BM_DBSETFILTER(bCondition) — create bitmap filter by evaluating condition on all records func BmDbSetFilter(t *hbrt.Thread) { t.Frame(1, 0) defer t.EndProc() wam := getWA(t) if wam == nil { t.RetNil() return } area := wam.Current() if area == nil { t.RetNil() return } block := t.Local(1) if !block.IsBlock() { t.RetNil() return } rc, _ := area.RecCount() bm := hbrdd.NewBitmapFilter(rc) // Evaluate condition for every record blk := block.AsBlock() for r := uint32(1); r <= rc; r++ { area.GoTo(r) t.PendingParams2(0) blk.Fn(t) result := t.GetRetValue() if result.AsBool() { bm.Set(r) } } // Store bitmap on area (via pointer value for now) t.RetPointer(bm) } // BM_DBSEEKWILD(cPattern) — wildcard seek using bitmap func BmDbSeekWild(t *hbrt.Thread) { nParams := t.ParamCount() t.Frame(nParams, 0) defer t.EndProc() wam := getWA(t) if wam == nil { t.RetBool(false) return } area := wam.Current() if area == nil { t.RetBool(false) return } pattern := t.Local(1).AsString() pattern = strings.TrimRight(pattern, " ") // Simple wildcard: "Park*" → prefix match isPrefix := strings.HasSuffix(pattern, "*") if isPrefix { pattern = pattern[:len(pattern)-1] } rc, _ := area.RecCount() for r := uint32(1); r <= rc; r++ { area.GoTo(r) // Check first field (simplified — should check indexed field) v, _ := area.GetValue(0) s := strings.TrimRight(v.AsString(), " ") match := false if isPrefix { match = strings.HasPrefix(s, pattern) } else { match = s == pattern } if match { t.RetBool(true) return } } t.RetBool(false) } // BM_TURBO(lOnOff) → lOldValue — enable/disable turbo mode var bmTurbo bool func BmTurbo(t *hbrt.Thread) { nParams := t.ParamCount() t.Frame(nParams, 0) defer t.EndProc() old := bmTurbo if nParams >= 1 && !t.Local(1).IsNil() { bmTurbo = t.Local(1).AsBool() } t.RetBool(old) } // BM_DBGETFILTERARRAY() → aRecNos — get matching record numbers as array func BmDbGetFilterArray(t *hbrt.Thread) { t.Frame(0, 0) defer t.EndProc() t.RetVal(hbrt.MakeArray(0)) } // BM_DBSETFILTERARRAY(aRecNos) → NIL — set filter from array of record numbers func BmDbSetFilterArray(t *hbrt.Thread) { t.Frame(1, 0) defer t.EndProc() t.RetNil() } // BM_DBSETFILTERARRAYADD(aRecNos) → NIL — add records to bitmap func BmDbSetFilterArrayAdd(t *hbrt.Thread) { t.Frame(1, 0) defer t.EndProc() t.RetNil() } // BM_DBSETFILTERARRAYDEL(aRecNos) → NIL — remove records from bitmap func BmDbSetFilterArrayDel(t *hbrt.Thread) { t.Frame(1, 0) defer t.EndProc() t.RetNil() }