Or and Xor with extra bitmaps used _or_many/_xor_many, which apply a single word count to every input. The count came from pointersOf, whose length is the maximum over the extra slice only and ignores other, so a longer other lost its tail words. More generally a uniform count cannot combine operands of different lengths: a longer source is truncated and a shorter one is read past its end. Fold each source in with the single-operand SIMD primitive over its own length, matching the scalar reference in simd_generic.go. Fixes the amd64 accelerated and AVX-512 branches and the arm64 branch.
131 lines
3.3 KiB
Go
131 lines
3.3 KiB
Go
// Copyright (c) Roman Atachiants and contributors. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
|
|
|
//go:build !noasm && arm64
|
|
|
|
package bitmap
|
|
|
|
import "unsafe"
|
|
|
|
// And computes the intersection between two bitmaps and stores the result in the current bitmap
|
|
func (dst *Bitmap) And(other Bitmap, extra ...Bitmap) {
|
|
max := minlen(*dst, other, extra)
|
|
dst.shrink(max)
|
|
if max == 0 {
|
|
return
|
|
}
|
|
|
|
switch hardware {
|
|
case isAccelerated:
|
|
switch len(extra) {
|
|
case 0:
|
|
_and(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(max))
|
|
default:
|
|
vx, _ := pointersOf(other, extra)
|
|
_and_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
|
|
}
|
|
default:
|
|
and(*dst, max, other, extra)
|
|
return
|
|
}
|
|
}
|
|
|
|
// AndNot computes the difference between two bitmaps and stores the result in the current bitmap.
|
|
// Operation works as set subtract: dst - b
|
|
func (dst *Bitmap) AndNot(other Bitmap, extra ...Bitmap) {
|
|
max := minlen(*dst, other, extra)
|
|
if max == 0 {
|
|
return
|
|
}
|
|
|
|
switch hardware {
|
|
case isAccelerated:
|
|
switch len(extra) {
|
|
case 0:
|
|
_andn(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(max))
|
|
default:
|
|
vx, _ := pointersOf(other, extra)
|
|
_andn_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
|
|
}
|
|
default:
|
|
andn(*dst, max, other, extra)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Or computes the union between two bitmaps and stores the result in the current bitmap
|
|
func (dst *Bitmap) Or(other Bitmap, extra ...Bitmap) {
|
|
max := maxlen(*dst, other, extra)
|
|
if max == 0 {
|
|
return
|
|
}
|
|
|
|
dst.grow(max - 1)
|
|
switch hardware {
|
|
case isAccelerated:
|
|
switch len(extra) {
|
|
case 0:
|
|
_or(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
|
|
default:
|
|
// _or_many uses one word count for every input, so it cannot union
|
|
// bitmaps of different lengths. Union each source over its own.
|
|
if len(other) > 0 {
|
|
_or(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
|
|
}
|
|
for i := range extra {
|
|
if len(extra[i]) > 0 {
|
|
_or(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&extra[i][0]), uint64(len(extra[i])))
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
or(*dst, other, extra)
|
|
}
|
|
}
|
|
|
|
// Xor computes the symmetric difference between two bitmaps and stores the result in the current bitmap
|
|
func (dst *Bitmap) Xor(other Bitmap, extra ...Bitmap) {
|
|
max := maxlen(*dst, other, extra)
|
|
if max == 0 {
|
|
return
|
|
}
|
|
|
|
dst.grow(max - 1)
|
|
switch hardware {
|
|
case isAccelerated:
|
|
switch len(extra) {
|
|
case 0:
|
|
_xor(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
|
|
default:
|
|
// _xor_many uses one word count for every input, so it cannot combine
|
|
// bitmaps of different lengths. Fold in each source over its own.
|
|
if len(other) > 0 {
|
|
_xor(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
|
|
}
|
|
for i := range extra {
|
|
if len(extra[i]) > 0 {
|
|
_xor(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&extra[i][0]), uint64(len(extra[i])))
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
xor(*dst, other, extra)
|
|
}
|
|
}
|
|
|
|
// Count returns the number of elements in this bitmap
|
|
func (dst Bitmap) Count() int {
|
|
if len(dst) == 0 {
|
|
return 0
|
|
}
|
|
|
|
switch hardware {
|
|
case isAccelerated:
|
|
var res uint64
|
|
_count(unsafe.Pointer(&dst[0]), uint64(len(dst)), unsafe.Pointer(&res))
|
|
return int(res)
|
|
default:
|
|
return count(dst)
|
|
}
|
|
}
|