mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-24 19:30:06 +01:00
152 lines
2.5 KiB
Go
152 lines
2.5 KiB
Go
|
package logstorage
|
||
|
|
||
|
import (
|
||
|
"math/bits"
|
||
|
"sync"
|
||
|
|
||
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/slicesutil"
|
||
|
)
|
||
|
|
||
|
func getBitmap(bitsLen int) *bitmap {
|
||
|
v := bitmapPool.Get()
|
||
|
if v == nil {
|
||
|
v = &bitmap{}
|
||
|
}
|
||
|
bm := v.(*bitmap)
|
||
|
bm.init(bitsLen)
|
||
|
return bm
|
||
|
}
|
||
|
|
||
|
func putBitmap(bm *bitmap) {
|
||
|
bm.reset()
|
||
|
bitmapPool.Put(bm)
|
||
|
}
|
||
|
|
||
|
var bitmapPool sync.Pool
|
||
|
|
||
|
type bitmap struct {
|
||
|
a []uint64
|
||
|
bitsLen int
|
||
|
}
|
||
|
|
||
|
func (bm *bitmap) reset() {
|
||
|
bm.resetBits()
|
||
|
bm.a = bm.a[:0]
|
||
|
|
||
|
bm.bitsLen = 0
|
||
|
}
|
||
|
|
||
|
func (bm *bitmap) copyFrom(src *bitmap) {
|
||
|
bm.reset()
|
||
|
|
||
|
bm.a = append(bm.a[:0], src.a...)
|
||
|
bm.bitsLen = src.bitsLen
|
||
|
}
|
||
|
|
||
|
func (bm *bitmap) init(bitsLen int) {
|
||
|
a := bm.a
|
||
|
wordsLen := (bitsLen + 63) / 64
|
||
|
a = slicesutil.SetLength(a, wordsLen)
|
||
|
bm.a = a
|
||
|
bm.bitsLen = bitsLen
|
||
|
}
|
||
|
|
||
|
func (bm *bitmap) resetBits() {
|
||
|
a := bm.a
|
||
|
for i := range a {
|
||
|
a[i] = 0
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (bm *bitmap) setBits() {
|
||
|
a := bm.a
|
||
|
for i := range a {
|
||
|
a[i] = ^uint64(0)
|
||
|
}
|
||
|
tailBits := bm.bitsLen % 64
|
||
|
if tailBits > 0 && len(a) > 0 {
|
||
|
// Zero bits outside bitsLen at the last word
|
||
|
a[len(a)-1] &= (uint64(1) << tailBits) - 1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (bm *bitmap) isZero() bool {
|
||
|
for _, word := range bm.a {
|
||
|
if word != 0 {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (bm *bitmap) areAllBitsSet() bool {
|
||
|
a := bm.a
|
||
|
for i, word := range a {
|
||
|
if word != (1<<64)-1 {
|
||
|
if i+1 < len(a) {
|
||
|
return false
|
||
|
}
|
||
|
tailBits := bm.bitsLen % 64
|
||
|
if tailBits == 0 || word != (uint64(1)<<tailBits)-1 {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (bm *bitmap) andNot(x *bitmap) {
|
||
|
if bm.bitsLen != x.bitsLen {
|
||
|
logger.Panicf("BUG: cannot merge bitmaps with distinct lengths; %d vs %d", bm.bitsLen, x.bitsLen)
|
||
|
}
|
||
|
a := bm.a
|
||
|
b := x.a
|
||
|
for i := range a {
|
||
|
a[i] &= ^b[i]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (bm *bitmap) or(x *bitmap) {
|
||
|
if bm.bitsLen != x.bitsLen {
|
||
|
logger.Panicf("BUG: cannot merge bitmaps with distinct lengths; %d vs %d", bm.bitsLen, x.bitsLen)
|
||
|
}
|
||
|
a := bm.a
|
||
|
b := x.a
|
||
|
for i := range a {
|
||
|
a[i] |= b[i]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// forEachSetBit calls f for each set bit and clears that bit if f returns false
|
||
|
func (bm *bitmap) forEachSetBit(f func(idx int) bool) {
|
||
|
a := bm.a
|
||
|
bitsLen := bm.bitsLen
|
||
|
for i, word := range a {
|
||
|
if word == 0 {
|
||
|
continue
|
||
|
}
|
||
|
for j := 0; j < 64; j++ {
|
||
|
mask := uint64(1) << j
|
||
|
if (word & mask) == 0 {
|
||
|
continue
|
||
|
}
|
||
|
idx := i*64 + j
|
||
|
if idx >= bitsLen {
|
||
|
break
|
||
|
}
|
||
|
if !f(idx) {
|
||
|
a[i] &= ^mask
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (bm *bitmap) onesCount() int {
|
||
|
n := 0
|
||
|
for _, word := range bm.a {
|
||
|
n += bits.OnesCount64(word)
|
||
|
}
|
||
|
return n
|
||
|
}
|