Upstream kelindar/bitmap state of the touched files before 7c356f442d

This commit is contained in:
upstream committed 2026-09-23 13:30:32 +02:00
1 parent 666c48ccf8
commit 58b05bdfdd
4 files changed
+12 -139

No files matched your search

-30
View File
@@ -236,36 +236,6 @@ func dimensionsOf(n, m int) uint64 {
// pointersOf returns a pointer to an array containing pointers to the // pointersOf returns a pointer to an array containing pointers to the
// first element of each bitmap and the maximum length of all bitmaps // first element of each bitmap and the maximum length of all bitmaps
// simdBinary is one of the accelerated two-operand primitives.
type simdBinary func(dst, src unsafe.Pointer, n uint64)
// uniformLen returns the word count shared by every source, or zero when the sources
// differ in length. The _many primitives apply a single count to all of their inputs,
// so they can only combine sources that are all the same length.
func uniformLen(other Bitmap, extra []Bitmap) int {
n := len(other)
for i := range extra {
if len(extra[i]) != n {
return 0
}
}
return n
}
// foldEach applies op to every source in turn, each over its own length. This is what
// ragged inputs need: a longer source would be truncated by a shared count, a shorter
// one read past its end.
func foldEach(dst *Bitmap, op simdBinary, other Bitmap, extra []Bitmap) {
if len(other) > 0 {
op(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
}
for i := range extra {
if len(extra[i]) > 0 {
op(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&extra[i][0]), uint64(len(extra[i])))
}
}
}
func pointersOf(other Bitmap, extra []Bitmap) (unsafe.Pointer, int) { func pointersOf(other Bitmap, extra []Bitmap) (unsafe.Pointer, int) {
out := make([]unsafe.Pointer, len(extra)+1) out := make([]unsafe.Pointer, len(extra)+1)
out[0] = unsafe.Pointer(&other[0]) out[0] = unsafe.Pointer(&other[0])
+8 -28
View File
@@ -83,26 +83,16 @@ func (dst *Bitmap) Or(other Bitmap, extra ...Bitmap) {
case 0: case 0:
_or(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other))) _or(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
default: default:
// _or_many applies one word count to every input, so it only fits vx, max := pointersOf(other, extra)
// sources that share a length; ragged ones are folded in one by one. _or_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
if n := uniformLen(other, extra); n > 0 {
vx, _ := pointersOf(other, extra)
_or_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(n, len(extra)+1))
} else {
foldEach(dst, _or, other, extra)
}
} }
case isAVX512: case isAVX512:
switch len(extra) { switch len(extra) {
case 0: case 0:
_or_avx512(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other))) _or_avx512(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
default: default:
if n := uniformLen(other, extra); n > 0 { vx, max := pointersOf(other, extra)
vx, _ := pointersOf(other, extra) _or_many_avx512(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
_or_many_avx512(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(n, len(extra)+1))
} else {
foldEach(dst, _or_avx512, other, extra)
}
} }
default: default:
or(*dst, other, extra) or(*dst, other, extra)
@@ -123,26 +113,16 @@ func (dst *Bitmap) Xor(other Bitmap, extra ...Bitmap) {
case 0: case 0:
_xor(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other))) _xor(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
default: default:
// _xor_many applies one word count to every input, so it only fits vx, max := pointersOf(other, extra)
// sources that share a length; ragged ones are folded in one by one. _xor_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
if n := uniformLen(other, extra); n > 0 {
vx, _ := pointersOf(other, extra)
_xor_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(n, len(extra)+1))
} else {
foldEach(dst, _xor, other, extra)
}
} }
case isAVX512: case isAVX512:
switch len(extra) { switch len(extra) {
case 0: case 0:
_xor_avx512(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other))) _xor_avx512(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
default: default:
if n := uniformLen(other, extra); n > 0 { vx, max := pointersOf(other, extra)
vx, _ := pointersOf(other, extra) _xor_many_avx512(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
_xor_many_avx512(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(n, len(extra)+1))
} else {
foldEach(dst, _xor_avx512, other, extra)
}
} }
default: default:
xor(*dst, other, extra) xor(*dst, other, extra)
+4 -16
View File
@@ -67,14 +67,8 @@ func (dst *Bitmap) Or(other Bitmap, extra ...Bitmap) {
case 0: case 0:
_or(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other))) _or(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
default: default:
// _or_many applies one word count to every input, so it only fits vx, max := pointersOf(other, extra)
// sources that share a length; ragged ones are folded in one by one. _or_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
if n := uniformLen(other, extra); n > 0 {
vx, _ := pointersOf(other, extra)
_or_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(n, len(extra)+1))
} else {
foldEach(dst, _or, other, extra)
}
} }
default: default:
or(*dst, other, extra) or(*dst, other, extra)
@@ -95,14 +89,8 @@ func (dst *Bitmap) Xor(other Bitmap, extra ...Bitmap) {
case 0: case 0:
_xor(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other))) _xor(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
default: default:
// _xor_many applies one word count to every input, so it only fits vx, max := pointersOf(other, extra)
// sources that share a length; ragged ones are folded in one by one. _xor_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
if n := uniformLen(other, extra); n > 0 {
vx, _ := pointersOf(other, extra)
_xor_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(n, len(extra)+1))
} else {
foldEach(dst, _xor, other, extra)
}
} }
default: default:
xor(*dst, other, extra) xor(*dst, other, extra)
-65
View File
@@ -130,25 +130,6 @@ func BenchmarkMany(b *testing.B) {
run(b, "and4-batch", func(index Bitmap) { run(b, "and4-batch", func(index Bitmap) {
index.And(other, other, other, other) index.And(other, other, other, other)
}) })
run(b, "or4-batch", func(index Bitmap) {
index.Or(other, other, other, other)
})
run(b, "xor4-batch", func(index Bitmap) {
index.Xor(other, other, other, other)
})
shorter := make(Bitmap, 1000000/64/2)
shorter.Set(1000000 / 2)
run(b, "or4-batch-ragged", func(index Bitmap) {
index.Or(other, other, shorter, other)
})
run(b, "xor4-batch-ragged", func(index Bitmap) {
index.Xor(other, other, shorter, other)
})
} }
func TestSetRemove(t *testing.T) { func TestSetRemove(t *testing.T) {
@@ -648,49 +629,3 @@ func testTruthTables(t *testing.T) {
assert.Equal(t, 0b0110, int(a[0])) assert.Equal(t, 0b0110, int(a[0]))
} }
} }
func TestOr_ExtraDifferentBitmapSizes(t *testing.T) {
// Ragged inputs: every set bit must survive regardless of which is longest.
var dst Bitmap
dst.Set(1) // word 0
dst.Set(70) // word 1
var other Bitmap
other.Set(3) // word 0
other.Set(200) // word 3, beyond every extra bitmap
var short Bitmap
short.Set(5) // word 0 only
var mid Bitmap
mid.Set(130) // word 2
dst.Or(other, short, mid)
want := []uint32{1, 70, 3, 200, 5, 130}
for _, v := range want {
assert.True(t, dst.Contains(v), "missing bit "+strconv.Itoa(int(v)))
}
assert.Equal(t, len(want), dst.Count())
}
func TestXor_ExtraDifferentBitmapSizes(t *testing.T) {
var dst Bitmap
dst.Set(1)
dst.Set(200) // shared with other, must cancel out
var other Bitmap
other.Set(200) // cancels dst's bit 200
other.Set(201) // survives, beyond every extra bitmap
var short Bitmap
short.Set(5)
dst.Xor(other, short)
assert.True(t, dst.Contains(1))
assert.False(t, dst.Contains(200), "bit 200 should cancel")
assert.True(t, dst.Contains(201), "bit 201 from longer source must survive")
assert.True(t, dst.Contains(5))
assert.Equal(t, 3, dst.Count())
}