Skip to content

Commit 56479e5

Browse files
committed
Optimize BSI64 BatchEqual cube patterns
1 parent 4cc8e21 commit 56479e5

2 files changed

Lines changed: 72 additions & 0 deletions

File tree

roaring64/bsi64.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,12 @@ func (b *BSI) BatchEqual(parallelism int, values []int64) *Bitmap {
10041004
}
10051005

10061006
sort.Slice(vals, func(i, j int) bool { return vals[i] < vals[j] })
1007+
if result, ok := b.matchInt64Cube(vals, bitCount); ok {
1008+
if b.runOptimized {
1009+
result.RunOptimize()
1010+
}
1011+
return result
1012+
}
10071013
result := b.matchInt64Trie(vals, bitCount, &b.eBM, false)
10081014
if b.runOptimized {
10091015
result.RunOptimize()
@@ -1028,6 +1034,56 @@ func encodeBSI64Value(value int64, bitCount int) uint64 {
10281034
return uint64(value) & mask
10291035
}
10301036

1037+
func (b *BSI) matchInt64Cube(vals []uint64, bitCount int) (*Bitmap, bool) {
1038+
if bitCount >= 63 {
1039+
return nil, false
1040+
}
1041+
widthMask := (uint64(1) << uint(bitCount+1)) - 1
1042+
fixedOnes := vals[0] & widthMask
1043+
fixedZeros := ^vals[0] & widthMask
1044+
for _, v := range vals[1:] {
1045+
fixedOnes &= v
1046+
fixedZeros &= ^v & widthMask
1047+
}
1048+
1049+
variableMask := ^(fixedOnes | fixedZeros) & widthMask
1050+
combinations := uint64(1) << uint(countBSI64Bits(variableMask))
1051+
if uint64(len(vals)) != combinations {
1052+
return nil, false
1053+
}
1054+
for _, v := range vals {
1055+
if v&fixedOnes != fixedOnes || (^v)&fixedZeros != fixedZeros {
1056+
return nil, false
1057+
}
1058+
}
1059+
1060+
result := b.eBM.Clone()
1061+
for i := 0; i <= bitCount; i++ {
1062+
bit := uint64(1) << uint(i)
1063+
if variableMask&bit != 0 {
1064+
continue
1065+
}
1066+
if fixedOnes&bit != 0 {
1067+
result.And(&b.bA[i])
1068+
} else {
1069+
result.AndNot(&b.bA[i])
1070+
}
1071+
if result.IsEmpty() {
1072+
break
1073+
}
1074+
}
1075+
return result, true
1076+
}
1077+
1078+
func countBSI64Bits(value uint64) int {
1079+
count := 0
1080+
for value != 0 {
1081+
value &= value - 1
1082+
count++
1083+
}
1084+
return count
1085+
}
1086+
10311087
func (b *BSI) matchInt64Trie(vals []uint64, p int, prefix *Bitmap, owned bool) *Bitmap {
10321088
if prefix.IsEmpty() {
10331089
if owned {

roaring64/bsi64_batch_equal_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,22 @@ func TestBSI64BatchEqualConsistentWithGetValue(t *testing.T) {
135135
}
136136
}
137137

138+
func TestBSI64BatchEqualBitCubePattern(t *testing.T) {
139+
bsi := NewDefaultBSI()
140+
for col := uint64(0); col < 512; col++ {
141+
bsi.SetValue(col, int64(col%256))
142+
}
143+
144+
odds := make([]int64, 0, 128)
145+
for v := int64(1); v < 256; v += 2 {
146+
odds = append(odds, v)
147+
}
148+
149+
expected := expectedBSI64BatchEqual(bsi, odds)
150+
actual := bsi.BatchEqual(0, odds)
151+
assert.True(t, actual.Equals(expected), "expected %v got %v", expected.ToArray(), actual.ToArray())
152+
}
153+
138154
func TestBSI64BatchEqualExistenceAuthority(t *testing.T) {
139155
ebm := BitmapOf(1)
140156
plane := BitmapOf(1, 2)

0 commit comments

Comments
 (0)