- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline - Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch - RTL: 351 Harbour-compatible functions - RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization - Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec) - HB_FUNC API: Full Harbour C API compatible Go bridge - Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT - Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST - Macro Compiler: Runtime AST parsing and evaluation - Debugger: TUI debugger with source display, breakpoints, stepping - FRB: Native + Pcode dual mode runtime binary - Tests: 13 packages ALL PASS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
238 lines
6.5 KiB
Go
238 lines
6.5 KiB
Go
package hbrdd
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// === Unit Tests ===
|
|
|
|
func TestBitmap_Basic(t *testing.T) {
|
|
bm := NewBitmapFilter(100)
|
|
bm.Set(1); bm.Set(50); bm.Set(100)
|
|
if !bm.Test(1) || !bm.Test(50) || !bm.Test(100) { t.Error("Set bits should test true") }
|
|
if bm.Test(2) || bm.Test(99) { t.Error("Unset bits should test false") }
|
|
if bm.Count() != 3 { t.Errorf("Count = %d, want 3", bm.Count()) }
|
|
}
|
|
|
|
func TestBitmap_NextSet(t *testing.T) {
|
|
bm := NewBitmapFilter(1000)
|
|
bm.Set(10); bm.Set(100); bm.Set(500); bm.Set(999)
|
|
if n := bm.NextSet(1); n != 10 { t.Errorf("NextSet(1) = %d, want 10", n) }
|
|
if n := bm.NextSet(11); n != 100 { t.Errorf("NextSet(11) = %d, want 100", n) }
|
|
if n := bm.NextSet(501); n != 999 { t.Errorf("NextSet(501) = %d, want 999", n) }
|
|
if n := bm.NextSet(1000); n != 0 { t.Errorf("NextSet(1000) = %d, want 0", n) }
|
|
}
|
|
|
|
func TestBitmap_PrevSet(t *testing.T) {
|
|
bm := NewBitmapFilter(1000)
|
|
bm.Set(10); bm.Set(100); bm.Set(500); bm.Set(999)
|
|
if n := bm.PrevSet(1000); n != 999 { t.Errorf("PrevSet(1000) = %d, want 999", n) }
|
|
if n := bm.PrevSet(998); n != 500 { t.Errorf("PrevSet(998) = %d, want 500", n) }
|
|
if n := bm.PrevSet(99); n != 10 { t.Errorf("PrevSet(99) = %d, want 10", n) }
|
|
if n := bm.PrevSet(9); n != 0 { t.Errorf("PrevSet(9) = %d, want 0", n) }
|
|
}
|
|
|
|
func TestBitmap_Full(t *testing.T) {
|
|
bm := NewBitmapFilterFull(100)
|
|
if bm.Count() != 100 { t.Errorf("Full count = %d, want 100", bm.Count()) }
|
|
bm.Clear(50)
|
|
if bm.Count() != 99 { t.Errorf("After clear = %d, want 99", bm.Count()) }
|
|
if bm.Test(50) { t.Error("Cleared bit should be false") }
|
|
// Verify no excess bits
|
|
if bm.Test(101) { t.Error("Bit 101 should be false (past maxRec)") }
|
|
}
|
|
|
|
func TestBitmap_FullEdge(t *testing.T) {
|
|
// Test exact 64-bit boundary
|
|
bm := NewBitmapFilterFull(64)
|
|
if bm.Count() != 64 { t.Errorf("Full(64) = %d", bm.Count()) }
|
|
bm2 := NewBitmapFilterFull(65)
|
|
if bm2.Count() != 65 { t.Errorf("Full(65) = %d", bm2.Count()) }
|
|
bm3 := NewBitmapFilterFull(128)
|
|
if bm3.Count() != 128 { t.Errorf("Full(128) = %d", bm3.Count()) }
|
|
}
|
|
|
|
func TestBitmap_And(t *testing.T) {
|
|
a := NewBitmapFilter(100)
|
|
b := NewBitmapFilter(100)
|
|
a.Set(1); a.Set(2); a.Set(3)
|
|
b.Set(2); b.Set(3); b.Set(4)
|
|
result := a.And(b)
|
|
if result.Count() != 2 { t.Errorf("AND count = %d, want 2", result.Count()) }
|
|
if !result.Test(2) || !result.Test(3) { t.Error("AND should have 2,3") }
|
|
}
|
|
|
|
func TestBitmap_Or(t *testing.T) {
|
|
a := NewBitmapFilter(100)
|
|
b := NewBitmapFilter(100)
|
|
a.Set(1); a.Set(2)
|
|
b.Set(3); b.Set(4)
|
|
result := a.Or(b)
|
|
if result.Count() != 4 { t.Errorf("OR count = %d, want 4", result.Count()) }
|
|
}
|
|
|
|
func TestBitmap_AndNot(t *testing.T) {
|
|
a := NewBitmapFilterFull(100)
|
|
b := NewBitmapFilter(100)
|
|
b.Set(1); b.Set(50); b.Set(100)
|
|
result := a.AndNot(b)
|
|
if result.Count() != 97 { t.Errorf("ANDNOT count = %d, want 97", result.Count()) }
|
|
if result.Test(1) || result.Test(50) || result.Test(100) { t.Error("ANDNOT should exclude 1,50,100") }
|
|
if !result.Test(2) { t.Error("ANDNOT should include 2") }
|
|
}
|
|
|
|
func TestBitmap_Not(t *testing.T) {
|
|
bm := NewBitmapFilter(64)
|
|
bm.Set(1)
|
|
inv := bm.Not()
|
|
if inv.Test(1) { t.Error("NOT should clear bit 1") }
|
|
if !inv.Test(2) { t.Error("NOT should set bit 2") }
|
|
if inv.Count() != 63 { t.Errorf("NOT count = %d, want 63", inv.Count()) }
|
|
}
|
|
|
|
func TestBitmap_InPlace(t *testing.T) {
|
|
a := NewBitmapFilterFull(100)
|
|
b := NewBitmapFilter(100)
|
|
b.Set(10); b.Set(20); b.Set(30)
|
|
a.AndInPlace(b)
|
|
if a.Count() != 3 { t.Errorf("AndInPlace count = %d, want 3", a.Count()) }
|
|
|
|
c := NewBitmapFilter(100)
|
|
c.Set(40); c.Set(50)
|
|
a.OrInPlace(c)
|
|
if a.Count() != 5 { t.Errorf("OrInPlace count = %d, want 5", a.Count()) }
|
|
}
|
|
|
|
func TestBitmap_Parallel(t *testing.T) {
|
|
bm := BuildParallel(10000, func(r uint32) bool {
|
|
return r%10 == 0 // every 10th record
|
|
})
|
|
if bm.Count() != 1000 { t.Errorf("Parallel count = %d, want 1000", bm.Count()) }
|
|
if !bm.Test(10) { t.Error("Record 10 should match") }
|
|
if bm.Test(11) { t.Error("Record 11 should not match") }
|
|
}
|
|
|
|
// === Benchmarks ===
|
|
|
|
func BenchmarkBitmap_NextSet_Sparse(b *testing.B) {
|
|
bm := NewBitmapFilter(1000000)
|
|
for i := uint32(1); i <= 1000000; i += 100 {
|
|
bm.Set(i)
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
rec := uint32(1)
|
|
for rec != 0 {
|
|
rec = bm.NextSet(rec + 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkBitmap_PrevSet_Sparse(b *testing.B) {
|
|
bm := NewBitmapFilter(1000000)
|
|
for i := uint32(1); i <= 1000000; i += 100 {
|
|
bm.Set(i)
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
rec := bm.maxRec
|
|
for rec != 0 {
|
|
rec = bm.PrevSet(rec - 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkBitmap_NextSet_Dense(b *testing.B) {
|
|
bm := NewBitmapFilterFull(1000000)
|
|
for i := uint32(1); i <= 1000000; i += 100 {
|
|
bm.Clear(i)
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
count := 0
|
|
rec := uint32(1)
|
|
for rec != 0 {
|
|
count++
|
|
rec = bm.NextSet(rec + 1)
|
|
if count > 1000000 { break }
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkBitmap_SequentialScan(b *testing.B) {
|
|
records := make([]bool, 1000000)
|
|
for i := 0; i < len(records); i += 100 {
|
|
records[i] = true
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
count := 0
|
|
for _, match := range records {
|
|
if match { count++ }
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkBitmap_And_1M(b *testing.B) {
|
|
a := NewBitmapFilterFull(1000000)
|
|
bm := NewBitmapFilterFull(1000000)
|
|
for i := uint32(1); i <= 1000000; i += 2 { a.Clear(i) }
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
a.And(bm)
|
|
}
|
|
}
|
|
|
|
func BenchmarkBitmap_AndInPlace_1M(b *testing.B) {
|
|
template := NewBitmapFilterFull(1000000)
|
|
other := NewBitmapFilterFull(1000000)
|
|
for i := uint32(1); i <= 1000000; i += 2 { other.Clear(i) }
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
bm := NewBitmapFilterFull(1000000)
|
|
copy(bm.bits, template.bits)
|
|
bm.count = template.count
|
|
bm.AndInPlace(other)
|
|
}
|
|
}
|
|
|
|
func BenchmarkBitmap_Or_1M(b *testing.B) {
|
|
a := NewBitmapFilter(1000000)
|
|
bm := NewBitmapFilter(1000000)
|
|
for i := uint32(1); i <= 1000000; i += 3 { a.Set(i) }
|
|
for i := uint32(1); i <= 1000000; i += 5 { bm.Set(i) }
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
a.Or(bm)
|
|
}
|
|
}
|
|
|
|
func BenchmarkBitmap_AndNot_1M(b *testing.B) {
|
|
a := NewBitmapFilterFull(1000000)
|
|
bm := NewBitmapFilter(1000000)
|
|
for i := uint32(1); i <= 1000000; i += 3 { bm.Set(i) }
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
a.AndNot(bm)
|
|
}
|
|
}
|
|
|
|
func BenchmarkBitmap_Parallel_1M(b *testing.B) {
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
BuildParallel(1000000, func(r uint32) bool {
|
|
return r%100 == 0
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkBitmap_Sequential_1M(b *testing.B) {
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
bm := NewBitmapFilter(1000000)
|
|
for r := uint32(1); r <= 1000000; r++ {
|
|
if r%100 == 0 { bm.Set(r) }
|
|
}
|
|
}
|
|
}
|