Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1151 lines
27 KiB
1151 lines
27 KiB
package roaring |
|
|
|
import ( |
|
"fmt" |
|
"unsafe" |
|
) |
|
|
|
//go:generate msgp -unexported |
|
|
|
type bitmapContainer struct { |
|
cardinality int |
|
bitmap []uint64 |
|
} |
|
|
|
func (bc bitmapContainer) String() string { |
|
var s string |
|
for it := bc.getShortIterator(); it.hasNext(); { |
|
s += fmt.Sprintf("%v, ", it.next()) |
|
} |
|
return s |
|
} |
|
|
|
func newBitmapContainer() *bitmapContainer { |
|
p := new(bitmapContainer) |
|
size := (1 << 16) / 64 |
|
p.bitmap = make([]uint64, size, size) |
|
return p |
|
} |
|
|
|
func newBitmapContainerwithRange(firstOfRun, lastOfRun int) *bitmapContainer { |
|
bc := newBitmapContainer() |
|
bc.cardinality = lastOfRun - firstOfRun + 1 |
|
if bc.cardinality == maxCapacity { |
|
fill(bc.bitmap, uint64(0xffffffffffffffff)) |
|
} else { |
|
firstWord := firstOfRun / 64 |
|
lastWord := lastOfRun / 64 |
|
zeroPrefixLength := uint64(firstOfRun & 63) |
|
zeroSuffixLength := uint64(63 - (lastOfRun & 63)) |
|
|
|
fillRange(bc.bitmap, firstWord, lastWord+1, uint64(0xffffffffffffffff)) |
|
bc.bitmap[firstWord] ^= ((uint64(1) << zeroPrefixLength) - 1) |
|
blockOfOnes := (uint64(1) << zeroSuffixLength) - 1 |
|
maskOnLeft := blockOfOnes << (uint64(64) - zeroSuffixLength) |
|
bc.bitmap[lastWord] ^= maskOnLeft |
|
} |
|
return bc |
|
} |
|
|
|
func (bc *bitmapContainer) minimum() uint16 { |
|
for i := 0; i < len(bc.bitmap); i++ { |
|
w := bc.bitmap[i] |
|
if w != 0 { |
|
r := countTrailingZeros(w) |
|
return uint16(r + i*64) |
|
} |
|
} |
|
return MaxUint16 |
|
} |
|
|
|
// i should be non-zero |
|
func clz(i uint64) int { |
|
n := 1 |
|
x := uint32(i >> 32) |
|
if x == 0 { |
|
n += 32 |
|
x = uint32(i) |
|
} |
|
if x>>16 == 0 { |
|
n += 16 |
|
x = x << 16 |
|
} |
|
if x>>24 == 0 { |
|
n += 8 |
|
x = x << 8 |
|
} |
|
if x>>28 == 0 { |
|
n += 4 |
|
x = x << 4 |
|
} |
|
if x>>30 == 0 { |
|
n += 2 |
|
x = x << 2 |
|
} |
|
return n - int(x>>31) |
|
} |
|
|
|
func (bc *bitmapContainer) maximum() uint16 { |
|
for i := len(bc.bitmap); i > 0; i-- { |
|
w := bc.bitmap[i-1] |
|
if w != 0 { |
|
r := clz(w) |
|
return uint16((i-1)*64 + 63 - r) |
|
} |
|
} |
|
return uint16(0) |
|
} |
|
|
|
func (bc *bitmapContainer) iterate(cb func(x uint16) bool) bool { |
|
iterator := bitmapContainerShortIterator{bc, bc.NextSetBit(0)} |
|
|
|
for iterator.hasNext() { |
|
if !cb(iterator.next()) { |
|
return false |
|
} |
|
} |
|
|
|
return true |
|
} |
|
|
|
type bitmapContainerShortIterator struct { |
|
ptr *bitmapContainer |
|
i int |
|
} |
|
|
|
func (bcsi *bitmapContainerShortIterator) next() uint16 { |
|
j := bcsi.i |
|
bcsi.i = bcsi.ptr.NextSetBit(bcsi.i + 1) |
|
return uint16(j) |
|
} |
|
func (bcsi *bitmapContainerShortIterator) hasNext() bool { |
|
return bcsi.i >= 0 |
|
} |
|
|
|
func (bcsi *bitmapContainerShortIterator) peekNext() uint16 { |
|
return uint16(bcsi.i) |
|
} |
|
|
|
func (bcsi *bitmapContainerShortIterator) advanceIfNeeded(minval uint16) { |
|
if bcsi.hasNext() && bcsi.peekNext() < minval { |
|
bcsi.i = bcsi.ptr.NextSetBit(int(minval)) |
|
} |
|
} |
|
|
|
func newBitmapContainerShortIterator(a *bitmapContainer) *bitmapContainerShortIterator { |
|
return &bitmapContainerShortIterator{a, a.NextSetBit(0)} |
|
} |
|
|
|
func (bc *bitmapContainer) getShortIterator() shortPeekable { |
|
return newBitmapContainerShortIterator(bc) |
|
} |
|
|
|
type reverseBitmapContainerShortIterator struct { |
|
ptr *bitmapContainer |
|
i int |
|
} |
|
|
|
func (bcsi *reverseBitmapContainerShortIterator) next() uint16 { |
|
if bcsi.i == -1 { |
|
panic("reverseBitmapContainerShortIterator.next() going beyond what is available") |
|
} |
|
|
|
j := bcsi.i |
|
bcsi.i = bcsi.ptr.PrevSetBit(bcsi.i - 1) |
|
return uint16(j) |
|
} |
|
|
|
func (bcsi *reverseBitmapContainerShortIterator) hasNext() bool { |
|
return bcsi.i >= 0 |
|
} |
|
|
|
func newReverseBitmapContainerShortIterator(a *bitmapContainer) *reverseBitmapContainerShortIterator { |
|
if a.cardinality == 0 { |
|
return &reverseBitmapContainerShortIterator{a, -1} |
|
} |
|
return &reverseBitmapContainerShortIterator{a, int(a.maximum())} |
|
} |
|
|
|
func (bc *bitmapContainer) getReverseIterator() shortIterable { |
|
return newReverseBitmapContainerShortIterator(bc) |
|
} |
|
|
|
type bitmapContainerManyIterator struct { |
|
ptr *bitmapContainer |
|
base int |
|
bitset uint64 |
|
} |
|
|
|
func (bcmi *bitmapContainerManyIterator) nextMany(hs uint32, buf []uint32) int { |
|
n := 0 |
|
base := bcmi.base |
|
bitset := bcmi.bitset |
|
|
|
for n < len(buf) { |
|
if bitset == 0 { |
|
base++ |
|
if base >= len(bcmi.ptr.bitmap) { |
|
bcmi.base = base |
|
bcmi.bitset = bitset |
|
return n |
|
} |
|
bitset = bcmi.ptr.bitmap[base] |
|
continue |
|
} |
|
t := bitset & -bitset |
|
buf[n] = uint32(((base * 64) + int(popcount(t-1)))) | hs |
|
n = n + 1 |
|
bitset ^= t |
|
} |
|
|
|
bcmi.base = base |
|
bcmi.bitset = bitset |
|
return n |
|
} |
|
|
|
func (bcmi *bitmapContainerManyIterator) nextMany64(hs uint64, buf []uint64) int { |
|
n := 0 |
|
base := bcmi.base |
|
bitset := bcmi.bitset |
|
|
|
for n < len(buf) { |
|
if bitset == 0 { |
|
base++ |
|
if base >= len(bcmi.ptr.bitmap) { |
|
bcmi.base = base |
|
bcmi.bitset = bitset |
|
return n |
|
} |
|
bitset = bcmi.ptr.bitmap[base] |
|
continue |
|
} |
|
t := bitset & -bitset |
|
buf[n] = uint64(((base * 64) + int(popcount(t-1)))) | hs |
|
n = n + 1 |
|
bitset ^= t |
|
} |
|
|
|
bcmi.base = base |
|
bcmi.bitset = bitset |
|
return n |
|
} |
|
|
|
func newBitmapContainerManyIterator(a *bitmapContainer) *bitmapContainerManyIterator { |
|
return &bitmapContainerManyIterator{a, -1, 0} |
|
} |
|
|
|
func (bc *bitmapContainer) getManyIterator() manyIterable { |
|
return newBitmapContainerManyIterator(bc) |
|
} |
|
|
|
func (bc *bitmapContainer) getSizeInBytes() int { |
|
return len(bc.bitmap) * 8 // + bcBaseBytes |
|
} |
|
|
|
func (bc *bitmapContainer) serializedSizeInBytes() int { |
|
//return bc.Msgsize()// NOO! This breaks GetSerializedSizeInBytes |
|
return len(bc.bitmap) * 8 |
|
} |
|
|
|
const bcBaseBytes = int(unsafe.Sizeof(bitmapContainer{})) |
|
|
|
// bitmapContainer doesn't depend on card, always fully allocated |
|
func bitmapContainerSizeInBytes() int { |
|
return bcBaseBytes + (1<<16)/8 |
|
} |
|
|
|
func bitmapEquals(a, b []uint64) bool { |
|
if len(a) != len(b) { |
|
return false |
|
} |
|
for i, v := range a { |
|
if v != b[i] { |
|
return false |
|
} |
|
} |
|
return true |
|
} |
|
|
|
func (bc *bitmapContainer) fillLeastSignificant16bits(x []uint32, i int, mask uint32) { |
|
// TODO: should be written as optimized assembly |
|
pos := i |
|
base := mask |
|
for k := 0; k < len(bc.bitmap); k++ { |
|
bitset := bc.bitmap[k] |
|
for bitset != 0 { |
|
t := bitset & -bitset |
|
x[pos] = base + uint32(popcount(t-1)) |
|
pos++ |
|
bitset ^= t |
|
} |
|
base += 64 |
|
} |
|
} |
|
|
|
func (bc *bitmapContainer) equals(o container) bool { |
|
srb, ok := o.(*bitmapContainer) |
|
if ok { |
|
if srb.cardinality != bc.cardinality { |
|
return false |
|
} |
|
return bitmapEquals(bc.bitmap, srb.bitmap) |
|
} |
|
|
|
// use generic comparison |
|
if bc.getCardinality() != o.getCardinality() { |
|
return false |
|
} |
|
ait := o.getShortIterator() |
|
bit := bc.getShortIterator() |
|
|
|
for ait.hasNext() { |
|
if bit.next() != ait.next() { |
|
return false |
|
} |
|
} |
|
return true |
|
} |
|
|
|
func (bc *bitmapContainer) iaddReturnMinimized(i uint16) container { |
|
bc.iadd(i) |
|
if bc.isFull() { |
|
return newRunContainer16Range(0, MaxUint16) |
|
} |
|
return bc |
|
} |
|
|
|
func (bc *bitmapContainer) iadd(i uint16) bool { |
|
x := int(i) |
|
previous := bc.bitmap[x/64] |
|
mask := uint64(1) << (uint(x) % 64) |
|
newb := previous | mask |
|
bc.bitmap[x/64] = newb |
|
bc.cardinality += int((previous ^ newb) >> (uint(x) % 64)) |
|
return newb != previous |
|
} |
|
|
|
func (bc *bitmapContainer) iremoveReturnMinimized(i uint16) container { |
|
if bc.iremove(i) { |
|
if bc.cardinality == arrayDefaultMaxSize { |
|
return bc.toArrayContainer() |
|
} |
|
} |
|
return bc |
|
} |
|
|
|
// iremove returns true if i was found. |
|
func (bc *bitmapContainer) iremove(i uint16) bool { |
|
if bc.contains(i) { |
|
bc.cardinality-- |
|
bc.bitmap[i/64] &^= (uint64(1) << (i % 64)) |
|
return true |
|
} |
|
return false |
|
} |
|
|
|
func (bc *bitmapContainer) isFull() bool { |
|
return bc.cardinality == int(MaxUint16)+1 |
|
} |
|
|
|
func (bc *bitmapContainer) getCardinality() int { |
|
return bc.cardinality |
|
} |
|
|
|
func (bc *bitmapContainer) clone() container { |
|
ptr := bitmapContainer{bc.cardinality, make([]uint64, len(bc.bitmap))} |
|
copy(ptr.bitmap, bc.bitmap[:]) |
|
return &ptr |
|
} |
|
|
|
// add all values in range [firstOfRange,lastOfRange) |
|
func (bc *bitmapContainer) iaddRange(firstOfRange, lastOfRange int) container { |
|
bc.cardinality += setBitmapRangeAndCardinalityChange(bc.bitmap, firstOfRange, lastOfRange) |
|
return bc |
|
} |
|
|
|
// remove all values in range [firstOfRange,lastOfRange) |
|
func (bc *bitmapContainer) iremoveRange(firstOfRange, lastOfRange int) container { |
|
bc.cardinality += resetBitmapRangeAndCardinalityChange(bc.bitmap, firstOfRange, lastOfRange) |
|
if bc.getCardinality() <= arrayDefaultMaxSize { |
|
return bc.toArrayContainer() |
|
} |
|
return bc |
|
} |
|
|
|
// flip all values in range [firstOfRange,endx) |
|
func (bc *bitmapContainer) inot(firstOfRange, endx int) container { |
|
if endx-firstOfRange == maxCapacity { |
|
flipBitmapRange(bc.bitmap, firstOfRange, endx) |
|
bc.cardinality = maxCapacity - bc.cardinality |
|
} else if endx-firstOfRange > maxCapacity/2 { |
|
flipBitmapRange(bc.bitmap, firstOfRange, endx) |
|
bc.computeCardinality() |
|
} else { |
|
bc.cardinality += flipBitmapRangeAndCardinalityChange(bc.bitmap, firstOfRange, endx) |
|
} |
|
if bc.getCardinality() <= arrayDefaultMaxSize { |
|
return bc.toArrayContainer() |
|
} |
|
return bc |
|
} |
|
|
|
// flip all values in range [firstOfRange,endx) |
|
func (bc *bitmapContainer) not(firstOfRange, endx int) container { |
|
answer := bc.clone() |
|
return answer.inot(firstOfRange, endx) |
|
} |
|
|
|
func (bc *bitmapContainer) or(a container) container { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.orArray(x) |
|
case *bitmapContainer: |
|
return bc.orBitmap(x) |
|
case *runContainer16: |
|
if x.isFull() { |
|
return x.clone() |
|
} |
|
return x.orBitmapContainer(bc) |
|
} |
|
panic("unsupported container type") |
|
} |
|
|
|
func (bc *bitmapContainer) orCardinality(a container) int { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.orArrayCardinality(x) |
|
case *bitmapContainer: |
|
return bc.orBitmapCardinality(x) |
|
case *runContainer16: |
|
return x.orBitmapContainerCardinality(bc) |
|
} |
|
panic("unsupported container type") |
|
} |
|
|
|
func (bc *bitmapContainer) ior(a container) container { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.iorArray(x) |
|
case *bitmapContainer: |
|
return bc.iorBitmap(x) |
|
case *runContainer16: |
|
if x.isFull() { |
|
return x.clone() |
|
} |
|
for i := range x.iv { |
|
bc.iaddRange(int(x.iv[i].start), int(x.iv[i].last())+1) |
|
} |
|
if bc.isFull() { |
|
return newRunContainer16Range(0, MaxUint16) |
|
} |
|
//bc.computeCardinality() |
|
return bc |
|
} |
|
panic(fmt.Errorf("unsupported container type %T", a)) |
|
} |
|
|
|
func (bc *bitmapContainer) lazyIOR(a container) container { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.lazyIORArray(x) |
|
case *bitmapContainer: |
|
return bc.lazyIORBitmap(x) |
|
case *runContainer16: |
|
if x.isFull() { |
|
return x.clone() |
|
} |
|
|
|
// Manually inlined setBitmapRange function |
|
bitmap := bc.bitmap |
|
for _, iv := range x.iv { |
|
start := int(iv.start) |
|
end := int(iv.last()) + 1 |
|
if start >= end { |
|
continue |
|
} |
|
firstword := start / 64 |
|
endword := (end - 1) / 64 |
|
if firstword == endword { |
|
bitmap[firstword] |= (^uint64(0) << uint(start%64)) & (^uint64(0) >> (uint(-end) % 64)) |
|
continue |
|
} |
|
bitmap[firstword] |= ^uint64(0) << uint(start%64) |
|
for i := firstword + 1; i < endword; i++ { |
|
bitmap[i] = ^uint64(0) |
|
} |
|
bitmap[endword] |= ^uint64(0) >> (uint(-end) % 64) |
|
} |
|
bc.cardinality = invalidCardinality |
|
return bc |
|
} |
|
panic("unsupported container type") |
|
} |
|
|
|
func (bc *bitmapContainer) lazyOR(a container) container { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.lazyORArray(x) |
|
case *bitmapContainer: |
|
return bc.lazyORBitmap(x) |
|
case *runContainer16: |
|
if x.isFull() { |
|
return x.clone() |
|
} |
|
// TODO: implement lazy OR |
|
return x.orBitmapContainer(bc) |
|
|
|
} |
|
panic("unsupported container type") |
|
} |
|
|
|
func (bc *bitmapContainer) orArray(value2 *arrayContainer) container { |
|
answer := bc.clone().(*bitmapContainer) |
|
c := value2.getCardinality() |
|
for k := 0; k < c; k++ { |
|
v := value2.content[k] |
|
i := uint(v) >> 6 |
|
bef := answer.bitmap[i] |
|
aft := bef | (uint64(1) << (v % 64)) |
|
answer.bitmap[i] = aft |
|
answer.cardinality += int((bef - aft) >> 63) |
|
} |
|
return answer |
|
} |
|
|
|
func (bc *bitmapContainer) orArrayCardinality(value2 *arrayContainer) int { |
|
answer := 0 |
|
c := value2.getCardinality() |
|
for k := 0; k < c; k++ { |
|
// branchless: |
|
v := value2.content[k] |
|
i := uint(v) >> 6 |
|
bef := bc.bitmap[i] |
|
aft := bef | (uint64(1) << (v % 64)) |
|
answer += int((bef - aft) >> 63) |
|
} |
|
return answer |
|
} |
|
|
|
func (bc *bitmapContainer) orBitmap(value2 *bitmapContainer) container { |
|
answer := newBitmapContainer() |
|
for k := 0; k < len(answer.bitmap); k++ { |
|
answer.bitmap[k] = bc.bitmap[k] | value2.bitmap[k] |
|
} |
|
answer.computeCardinality() |
|
if answer.isFull() { |
|
return newRunContainer16Range(0, MaxUint16) |
|
} |
|
return answer |
|
} |
|
|
|
func (bc *bitmapContainer) orBitmapCardinality(value2 *bitmapContainer) int { |
|
return int(popcntOrSlice(bc.bitmap, value2.bitmap)) |
|
} |
|
|
|
func (bc *bitmapContainer) andBitmapCardinality(value2 *bitmapContainer) int { |
|
return int(popcntAndSlice(bc.bitmap, value2.bitmap)) |
|
} |
|
|
|
func (bc *bitmapContainer) computeCardinality() { |
|
bc.cardinality = int(popcntSlice(bc.bitmap)) |
|
} |
|
|
|
func (bc *bitmapContainer) iorArray(ac *arrayContainer) container { |
|
for k := range ac.content { |
|
vc := ac.content[k] |
|
i := uint(vc) >> 6 |
|
bef := bc.bitmap[i] |
|
aft := bef | (uint64(1) << (vc % 64)) |
|
bc.bitmap[i] = aft |
|
bc.cardinality += int((bef - aft) >> 63) |
|
} |
|
if bc.isFull() { |
|
return newRunContainer16Range(0, MaxUint16) |
|
} |
|
return bc |
|
} |
|
|
|
func (bc *bitmapContainer) iorBitmap(value2 *bitmapContainer) container { |
|
answer := bc |
|
answer.cardinality = 0 |
|
for k := 0; k < len(answer.bitmap); k++ { |
|
answer.bitmap[k] = bc.bitmap[k] | value2.bitmap[k] |
|
} |
|
answer.computeCardinality() |
|
if bc.isFull() { |
|
return newRunContainer16Range(0, MaxUint16) |
|
} |
|
return answer |
|
} |
|
|
|
func (bc *bitmapContainer) lazyIORArray(value2 *arrayContainer) container { |
|
answer := bc |
|
c := value2.getCardinality() |
|
for k := 0; k+3 < c; k += 4 { |
|
content := (*[4]uint16)(unsafe.Pointer(&value2.content[k])) |
|
vc0 := content[0] |
|
i0 := uint(vc0) >> 6 |
|
answer.bitmap[i0] = answer.bitmap[i0] | (uint64(1) << (vc0 % 64)) |
|
|
|
vc1 := content[1] |
|
i1 := uint(vc1) >> 6 |
|
answer.bitmap[i1] = answer.bitmap[i1] | (uint64(1) << (vc1 % 64)) |
|
|
|
vc2 := content[2] |
|
i2 := uint(vc2) >> 6 |
|
answer.bitmap[i2] = answer.bitmap[i2] | (uint64(1) << (vc2 % 64)) |
|
|
|
vc3 := content[3] |
|
i3 := uint(vc3) >> 6 |
|
answer.bitmap[i3] = answer.bitmap[i3] | (uint64(1) << (vc3 % 64)) |
|
} |
|
|
|
for k := c &^ 3; k < c; k++ { |
|
vc := value2.content[k] |
|
i := uint(vc) >> 6 |
|
answer.bitmap[i] = answer.bitmap[i] | (uint64(1) << (vc % 64)) |
|
} |
|
|
|
answer.cardinality = invalidCardinality |
|
return answer |
|
} |
|
|
|
func (bc *bitmapContainer) lazyORArray(value2 *arrayContainer) container { |
|
answer := bc.clone().(*bitmapContainer) |
|
return answer.lazyIORArray(value2) |
|
} |
|
|
|
func (bc *bitmapContainer) lazyIORBitmap(value2 *bitmapContainer) container { |
|
answer := bc |
|
for k := 0; k < len(answer.bitmap); k++ { |
|
answer.bitmap[k] = bc.bitmap[k] | value2.bitmap[k] |
|
} |
|
bc.cardinality = invalidCardinality |
|
return answer |
|
} |
|
|
|
func (bc *bitmapContainer) lazyORBitmap(value2 *bitmapContainer) container { |
|
answer := bc.clone().(*bitmapContainer) |
|
return answer.lazyIORBitmap(value2) |
|
} |
|
|
|
func (bc *bitmapContainer) xor(a container) container { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.xorArray(x) |
|
case *bitmapContainer: |
|
return bc.xorBitmap(x) |
|
case *runContainer16: |
|
return x.xorBitmap(bc) |
|
} |
|
panic("unsupported container type") |
|
} |
|
|
|
func (bc *bitmapContainer) xorArray(value2 *arrayContainer) container { |
|
answer := bc.clone().(*bitmapContainer) |
|
c := value2.getCardinality() |
|
for k := 0; k < c; k++ { |
|
vc := value2.content[k] |
|
index := uint(vc) >> 6 |
|
abi := answer.bitmap[index] |
|
mask := uint64(1) << (vc % 64) |
|
answer.cardinality += 1 - 2*int((abi&mask)>>(vc%64)) |
|
answer.bitmap[index] = abi ^ mask |
|
} |
|
if answer.cardinality <= arrayDefaultMaxSize { |
|
return answer.toArrayContainer() |
|
} |
|
return answer |
|
} |
|
|
|
func (bc *bitmapContainer) rank(x uint16) int { |
|
// TODO: rewrite in assembly |
|
leftover := (uint(x) + 1) & 63 |
|
if leftover == 0 { |
|
return int(popcntSlice(bc.bitmap[:(uint(x)+1)/64])) |
|
} |
|
return int(popcntSlice(bc.bitmap[:(uint(x)+1)/64]) + popcount(bc.bitmap[(uint(x)+1)/64]<<(64-leftover))) |
|
} |
|
|
|
func (bc *bitmapContainer) selectInt(x uint16) int { |
|
remaining := x |
|
for k := 0; k < len(bc.bitmap); k++ { |
|
w := popcount(bc.bitmap[k]) |
|
if uint16(w) > remaining { |
|
return k*64 + selectBitPosition(bc.bitmap[k], int(remaining)) |
|
} |
|
remaining -= uint16(w) |
|
} |
|
return -1 |
|
} |
|
|
|
func (bc *bitmapContainer) xorBitmap(value2 *bitmapContainer) container { |
|
newCardinality := int(popcntXorSlice(bc.bitmap, value2.bitmap)) |
|
|
|
if newCardinality > arrayDefaultMaxSize { |
|
answer := newBitmapContainer() |
|
for k := 0; k < len(answer.bitmap); k++ { |
|
answer.bitmap[k] = bc.bitmap[k] ^ value2.bitmap[k] |
|
} |
|
answer.cardinality = newCardinality |
|
if answer.isFull() { |
|
return newRunContainer16Range(0, MaxUint16) |
|
} |
|
return answer |
|
} |
|
ac := newArrayContainerSize(newCardinality) |
|
fillArrayXOR(ac.content, bc.bitmap, value2.bitmap) |
|
ac.content = ac.content[:newCardinality] |
|
return ac |
|
} |
|
|
|
func (bc *bitmapContainer) and(a container) container { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.andArray(x) |
|
case *bitmapContainer: |
|
return bc.andBitmap(x) |
|
case *runContainer16: |
|
if x.isFull() { |
|
return bc.clone() |
|
} |
|
return x.andBitmapContainer(bc) |
|
} |
|
panic("unsupported container type") |
|
} |
|
|
|
func (bc *bitmapContainer) andCardinality(a container) int { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.andArrayCardinality(x) |
|
case *bitmapContainer: |
|
return bc.andBitmapCardinality(x) |
|
case *runContainer16: |
|
return x.andBitmapContainerCardinality(bc) |
|
} |
|
panic("unsupported container type") |
|
} |
|
|
|
func (bc *bitmapContainer) intersects(a container) bool { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.intersectsArray(x) |
|
case *bitmapContainer: |
|
return bc.intersectsBitmap(x) |
|
case *runContainer16: |
|
return x.intersects(bc) |
|
|
|
} |
|
panic("unsupported container type") |
|
} |
|
|
|
func (bc *bitmapContainer) iand(a container) container { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.iandArray(x) |
|
case *bitmapContainer: |
|
return bc.iandBitmap(x) |
|
case *runContainer16: |
|
if x.isFull() { |
|
return bc.clone() |
|
} |
|
return bc.iandRun16(x) |
|
} |
|
panic("unsupported container type") |
|
} |
|
|
|
func (bc *bitmapContainer) iandRun16(rc *runContainer16) container { |
|
rcb := newBitmapContainerFromRun(rc) |
|
return bc.iandBitmap(rcb) |
|
} |
|
|
|
func (bc *bitmapContainer) iandArray(ac *arrayContainer) container { |
|
acb := ac.toBitmapContainer() |
|
return bc.iandBitmap(acb) |
|
} |
|
|
|
func (bc *bitmapContainer) andArray(value2 *arrayContainer) *arrayContainer { |
|
answer := newArrayContainerCapacity(len(value2.content)) |
|
answer.content = answer.content[:cap(answer.content)] |
|
c := value2.getCardinality() |
|
pos := 0 |
|
for k := 0; k < c; k++ { |
|
v := value2.content[k] |
|
answer.content[pos] = v |
|
pos += int(bc.bitValue(v)) |
|
} |
|
answer.content = answer.content[:pos] |
|
return answer |
|
} |
|
|
|
func (bc *bitmapContainer) andArrayCardinality(value2 *arrayContainer) int { |
|
c := value2.getCardinality() |
|
pos := 0 |
|
for k := 0; k < c; k++ { |
|
v := value2.content[k] |
|
pos += int(bc.bitValue(v)) |
|
} |
|
return pos |
|
} |
|
|
|
func (bc *bitmapContainer) getCardinalityInRange(start, end uint) int { |
|
if start >= end { |
|
return 0 |
|
} |
|
firstword := start / 64 |
|
endword := (end - 1) / 64 |
|
const allones = ^uint64(0) |
|
if firstword == endword { |
|
return int(popcount(bc.bitmap[firstword] & ((allones << (start % 64)) & (allones >> ((64 - end) & 63))))) |
|
} |
|
answer := popcount(bc.bitmap[firstword] & (allones << (start % 64))) |
|
answer += popcntSlice(bc.bitmap[firstword+1 : endword]) |
|
answer += popcount(bc.bitmap[endword] & (allones >> ((64 - end) & 63))) |
|
return int(answer) |
|
} |
|
|
|
func (bc *bitmapContainer) andBitmap(value2 *bitmapContainer) container { |
|
newcardinality := int(popcntAndSlice(bc.bitmap, value2.bitmap)) |
|
if newcardinality > arrayDefaultMaxSize { |
|
answer := newBitmapContainer() |
|
for k := 0; k < len(answer.bitmap); k++ { |
|
answer.bitmap[k] = bc.bitmap[k] & value2.bitmap[k] |
|
} |
|
answer.cardinality = newcardinality |
|
return answer |
|
} |
|
ac := newArrayContainerSize(newcardinality) |
|
fillArrayAND(ac.content, bc.bitmap, value2.bitmap) |
|
ac.content = ac.content[:newcardinality] //not sure why i need this |
|
return ac |
|
|
|
} |
|
|
|
func (bc *bitmapContainer) intersectsArray(value2 *arrayContainer) bool { |
|
c := value2.getCardinality() |
|
for k := 0; k < c; k++ { |
|
v := value2.content[k] |
|
if bc.contains(v) { |
|
return true |
|
} |
|
} |
|
return false |
|
} |
|
|
|
func (bc *bitmapContainer) intersectsBitmap(value2 *bitmapContainer) bool { |
|
for k := 0; k < len(bc.bitmap); k++ { |
|
if (bc.bitmap[k] & value2.bitmap[k]) != 0 { |
|
return true |
|
} |
|
} |
|
return false |
|
|
|
} |
|
|
|
func (bc *bitmapContainer) iandBitmap(value2 *bitmapContainer) container { |
|
newcardinality := int(popcntAndSlice(bc.bitmap, value2.bitmap)) |
|
for k := 0; k < len(bc.bitmap); k++ { |
|
bc.bitmap[k] = bc.bitmap[k] & value2.bitmap[k] |
|
} |
|
bc.cardinality = newcardinality |
|
|
|
if newcardinality <= arrayDefaultMaxSize { |
|
return newArrayContainerFromBitmap(bc) |
|
} |
|
return bc |
|
} |
|
|
|
func (bc *bitmapContainer) andNot(a container) container { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.andNotArray(x) |
|
case *bitmapContainer: |
|
return bc.andNotBitmap(x) |
|
case *runContainer16: |
|
return bc.andNotRun16(x) |
|
} |
|
panic("unsupported container type") |
|
} |
|
|
|
func (bc *bitmapContainer) andNotRun16(rc *runContainer16) container { |
|
rcb := rc.toBitmapContainer() |
|
return bc.andNotBitmap(rcb) |
|
} |
|
|
|
func (bc *bitmapContainer) iandNot(a container) container { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
return bc.iandNotArray(x) |
|
case *bitmapContainer: |
|
return bc.iandNotBitmapSurely(x) |
|
case *runContainer16: |
|
return bc.iandNotRun16(x) |
|
} |
|
panic("unsupported container type") |
|
} |
|
|
|
func (bc *bitmapContainer) iandNotArray(ac *arrayContainer) container { |
|
acb := ac.toBitmapContainer() |
|
return bc.iandNotBitmapSurely(acb) |
|
} |
|
|
|
func (bc *bitmapContainer) iandNotRun16(rc *runContainer16) container { |
|
rcb := rc.toBitmapContainer() |
|
return bc.iandNotBitmapSurely(rcb) |
|
} |
|
|
|
func (bc *bitmapContainer) andNotArray(value2 *arrayContainer) container { |
|
answer := bc.clone().(*bitmapContainer) |
|
c := value2.getCardinality() |
|
for k := 0; k < c; k++ { |
|
vc := value2.content[k] |
|
i := uint(vc) >> 6 |
|
oldv := answer.bitmap[i] |
|
newv := oldv &^ (uint64(1) << (vc % 64)) |
|
answer.bitmap[i] = newv |
|
answer.cardinality -= int((oldv ^ newv) >> (vc % 64)) |
|
} |
|
if answer.cardinality <= arrayDefaultMaxSize { |
|
return answer.toArrayContainer() |
|
} |
|
return answer |
|
} |
|
|
|
func (bc *bitmapContainer) andNotBitmap(value2 *bitmapContainer) container { |
|
newCardinality := int(popcntMaskSlice(bc.bitmap, value2.bitmap)) |
|
if newCardinality > arrayDefaultMaxSize { |
|
answer := newBitmapContainer() |
|
for k := 0; k < len(answer.bitmap); k++ { |
|
answer.bitmap[k] = bc.bitmap[k] &^ value2.bitmap[k] |
|
} |
|
answer.cardinality = newCardinality |
|
return answer |
|
} |
|
ac := newArrayContainerSize(newCardinality) |
|
fillArrayANDNOT(ac.content, bc.bitmap, value2.bitmap) |
|
return ac |
|
} |
|
|
|
func (bc *bitmapContainer) iandNotBitmapSurely(value2 *bitmapContainer) container { |
|
newCardinality := int(popcntMaskSlice(bc.bitmap, value2.bitmap)) |
|
for k := 0; k < len(bc.bitmap); k++ { |
|
bc.bitmap[k] = bc.bitmap[k] &^ value2.bitmap[k] |
|
} |
|
bc.cardinality = newCardinality |
|
if bc.getCardinality() <= arrayDefaultMaxSize { |
|
return bc.toArrayContainer() |
|
} |
|
return bc |
|
} |
|
|
|
func (bc *bitmapContainer) contains(i uint16) bool { //testbit |
|
x := uint(i) |
|
w := bc.bitmap[x>>6] |
|
mask := uint64(1) << (x & 63) |
|
return (w & mask) != 0 |
|
} |
|
|
|
func (bc *bitmapContainer) bitValue(i uint16) uint64 { |
|
x := uint(i) |
|
w := bc.bitmap[x>>6] |
|
return (w >> (x & 63)) & 1 |
|
} |
|
|
|
func (bc *bitmapContainer) loadData(arrayContainer *arrayContainer) { |
|
bc.cardinality = arrayContainer.getCardinality() |
|
c := arrayContainer.getCardinality() |
|
for k := 0; k < c; k++ { |
|
x := arrayContainer.content[k] |
|
i := int(x) / 64 |
|
bc.bitmap[i] |= (uint64(1) << uint(x%64)) |
|
} |
|
} |
|
|
|
func (bc *bitmapContainer) resetTo(a container) { |
|
switch x := a.(type) { |
|
case *arrayContainer: |
|
fill(bc.bitmap, 0) |
|
bc.loadData(x) |
|
|
|
case *bitmapContainer: |
|
bc.cardinality = x.cardinality |
|
copy(bc.bitmap, x.bitmap) |
|
|
|
case *runContainer16: |
|
bc.cardinality = len(x.iv) |
|
lastEnd := 0 |
|
for _, r := range x.iv { |
|
bc.cardinality += int(r.length) |
|
resetBitmapRange(bc.bitmap, lastEnd, int(r.start)) |
|
lastEnd = int(r.start+r.length) + 1 |
|
setBitmapRange(bc.bitmap, int(r.start), lastEnd) |
|
} |
|
resetBitmapRange(bc.bitmap, lastEnd, maxCapacity) |
|
|
|
default: |
|
panic("unsupported container type") |
|
} |
|
} |
|
|
|
func (bc *bitmapContainer) toArrayContainer() *arrayContainer { |
|
ac := &arrayContainer{} |
|
ac.loadData(bc) |
|
return ac |
|
} |
|
|
|
func (bc *bitmapContainer) fillArray(container []uint16) { |
|
//TODO: rewrite in assembly |
|
pos := 0 |
|
base := 0 |
|
for k := 0; k < len(bc.bitmap); k++ { |
|
bitset := bc.bitmap[k] |
|
for bitset != 0 { |
|
t := bitset & -bitset |
|
container[pos] = uint16((base + int(popcount(t-1)))) |
|
pos = pos + 1 |
|
bitset ^= t |
|
} |
|
base += 64 |
|
} |
|
} |
|
|
|
func (bc *bitmapContainer) NextSetBit(i int) int { |
|
x := i / 64 |
|
if x >= len(bc.bitmap) { |
|
return -1 |
|
} |
|
w := bc.bitmap[x] |
|
w = w >> uint(i%64) |
|
if w != 0 { |
|
return i + countTrailingZeros(w) |
|
} |
|
x++ |
|
for ; x < len(bc.bitmap); x++ { |
|
if bc.bitmap[x] != 0 { |
|
return (x * 64) + countTrailingZeros(bc.bitmap[x]) |
|
} |
|
} |
|
return -1 |
|
} |
|
|
|
func (bc *bitmapContainer) PrevSetBit(i int) int { |
|
if i < 0 { |
|
return -1 |
|
} |
|
x := i / 64 |
|
if x >= len(bc.bitmap) { |
|
return -1 |
|
} |
|
|
|
w := bc.bitmap[x] |
|
|
|
b := i % 64 |
|
|
|
w = w << uint(63-b) |
|
if w != 0 { |
|
return i - countLeadingZeros(w) |
|
} |
|
x-- |
|
for ; x >= 0; x-- { |
|
if bc.bitmap[x] != 0 { |
|
return (x * 64) + 63 - countLeadingZeros(bc.bitmap[x]) |
|
} |
|
} |
|
return -1 |
|
} |
|
|
|
// reference the java implementation |
|
// https://github.com/RoaringBitmap/RoaringBitmap/blob/master/src/main/java/org/roaringbitmap/BitmapContainer.java#L875-L892 |
|
// |
|
func (bc *bitmapContainer) numberOfRuns() int { |
|
if bc.cardinality == 0 { |
|
return 0 |
|
} |
|
|
|
var numRuns uint64 |
|
nextWord := bc.bitmap[0] |
|
|
|
for i := 0; i < len(bc.bitmap)-1; i++ { |
|
word := nextWord |
|
nextWord = bc.bitmap[i+1] |
|
numRuns += popcount((^word)&(word<<1)) + ((word >> 63) &^ nextWord) |
|
} |
|
|
|
word := nextWord |
|
numRuns += popcount((^word) & (word << 1)) |
|
if (word & 0x8000000000000000) != 0 { |
|
numRuns++ |
|
} |
|
|
|
return int(numRuns) |
|
} |
|
|
|
// convert to run or array *if needed* |
|
func (bc *bitmapContainer) toEfficientContainer() container { |
|
|
|
numRuns := bc.numberOfRuns() |
|
|
|
sizeAsRunContainer := runContainer16SerializedSizeInBytes(numRuns) |
|
sizeAsBitmapContainer := bitmapContainerSizeInBytes() |
|
card := bc.getCardinality() |
|
sizeAsArrayContainer := arrayContainerSizeInBytes(card) |
|
|
|
if sizeAsRunContainer <= minOfInt(sizeAsBitmapContainer, sizeAsArrayContainer) { |
|
return newRunContainer16FromBitmapContainer(bc) |
|
} |
|
if card <= arrayDefaultMaxSize { |
|
return bc.toArrayContainer() |
|
} |
|
return bc |
|
} |
|
|
|
func newBitmapContainerFromRun(rc *runContainer16) *bitmapContainer { |
|
|
|
if len(rc.iv) == 1 { |
|
return newBitmapContainerwithRange(int(rc.iv[0].start), int(rc.iv[0].last())) |
|
} |
|
|
|
bc := newBitmapContainer() |
|
for i := range rc.iv { |
|
setBitmapRange(bc.bitmap, int(rc.iv[i].start), int(rc.iv[i].last())+1) |
|
bc.cardinality += int(rc.iv[i].last()) + 1 - int(rc.iv[i].start) |
|
} |
|
//bc.computeCardinality() |
|
return bc |
|
} |
|
|
|
func (bc *bitmapContainer) containerType() contype { |
|
return bitmapContype |
|
} |
|
|
|
func (bc *bitmapContainer) addOffset(x uint16) []container { |
|
low := newBitmapContainer() |
|
high := newBitmapContainer() |
|
b := uint32(x) >> 6 |
|
i := uint32(x) % 64 |
|
end := uint32(1024) - b |
|
if i == 0 { |
|
copy(low.bitmap[b:], bc.bitmap[:end]) |
|
copy(high.bitmap[:b], bc.bitmap[end:]) |
|
} else { |
|
low.bitmap[b] = bc.bitmap[0] << i |
|
for k := uint32(1); k < end; k++ { |
|
newval := bc.bitmap[k] << i |
|
if newval == 0 { |
|
newval = bc.bitmap[k-1] >> (64 - i) |
|
} |
|
low.bitmap[b+k] = newval |
|
} |
|
for k := end; k < 1024; k++ { |
|
newval := bc.bitmap[k] << i |
|
if newval == 0 { |
|
newval = bc.bitmap[k-1] >> (64 - i) |
|
} |
|
high.bitmap[k-end] = newval |
|
} |
|
high.bitmap[b] = bc.bitmap[1023] >> (64 - i) |
|
} |
|
low.computeCardinality() |
|
high.computeCardinality() |
|
return []container{low, high} |
|
}
|
|
|