bitmap/run support for rle

This commit is contained in:
Todd Gruben 2017-06-12 15:59:26 -05:00 committed by Matt Jaffee
parent bf7a1bc08a
commit 93a7320cd9
2 changed files with 134 additions and 0 deletions

View file

@ -2252,6 +2252,32 @@ func (c *container) bitmapSetRange(i, j uint64) {
}
}
// xor's all bits in [i, j] with all true (inclusive) (c must be a bitmap container).
func (c *container) bitmapXorRange(i, j uint64) {
j += 1
x := i / 64
y := (j - 1) / 64
var X uint64 = maxBitmap << (i % 64)
var Y uint64 = maxBitmap >> (64 - (j % 64))
if x == y {
cnt := popcnt(c.bitmap[x])
c.bitmap[x] ^= (X & Y) //// flip
c.n += int(popcnt(c.bitmap[x]) - cnt)
} else {
cnt := popcnt(c.bitmap[x])
c.bitmap[x] ^= X
c.n += int(popcnt(c.bitmap[x]) - cnt)
for i := x + 1; i < y; i++ {
cnt = popcnt(c.bitmap[i])
c.bitmap[i] ^= maxBitmap
c.n += int(popcnt(c.bitmap[i]) - cnt)
}
cnt = popcnt(c.bitmap[y])
c.bitmap[y] ^= Y
c.n += int(popcnt(c.bitmap[y]) - cnt)
}
}
// zeroes all bits in [i, j] (inclusive) (c must be a bitmap container)
func (c *container) bitmapZeroRange(i, j uint64) {
j += 1
@ -3152,3 +3178,18 @@ func xorRunRun(a, b *container) *container {
}
return output
}
// xorRunRun computes the exclusive or of a bitmap and a run container.
func xorBitmapRun(a, b *container) *container {
output := a.clone()
for j := 0; j < len(b.runs); j++ {
output.bitmapXorRange(uint64(b.runs[j].start), uint64(b.runs[j].last))
}
if output.n < ArrayMaxSize && len(output.runs) > output.n/2 {
output.runToArray()
} else if len(output.runs) > RunMaxSize {
output.runToBitmap()
}
return output
}

View file

@ -1363,3 +1363,96 @@ func TestXorRunRun(t *testing.T) {
}
}
}
func TestBitmapFlipRange(t *testing.T) {
c := &container{bitmap: make([]uint64, bitmapN)}
tests := []struct {
bitmap []uint64
start uint64
last uint64
exp []uint64
expN int
}{
{
bitmap: []uint64{0x0000000000000000},
start: 0,
last: 2,
exp: []uint64{0x0000000000000007},
expN: 3,
},
{
bitmap: []uint64{0xF1},
start: 4,
last: 8,
exp: []uint64{0x101},
expN: 2,
},
{
bitmap: []uint64{0xAA},
start: 0,
last: 7,
exp: []uint64{0x55},
expN: 4,
},
{
bitmap: []uint64{0x0, 0x0000000000000000, 0x0000000000000000},
start: 63,
last: 128,
exp: []uint64{0x8000000000000000, 0xFFFFFFFFFFFFFFFF, 0x000000000000001},
expN: 66,
},
{
bitmap: []uint64{0x0, 0x00000000000000FF, 0x0000000000000000},
start: 63,
last: 128,
exp: []uint64{0x8000000000000000, 0xFFFFFFFFFFFFFF00, 0x000000000000001},
expN: 58,
},
{
bitmap: []uint64{0x0, 0x0, 0x0},
start: 129,
last: 131,
exp: []uint64{0x0000000000000000, 0x0000000000000000, 0x00000000000000E},
expN: 3,
},
}
for i, test := range tests {
for i, v := range test.bitmap {
c.bitmap[i] = v
}
c.n = c.countRange(0, 65535)
c.bitmapXorRange(test.start, test.last)
if !reflect.DeepEqual(c.bitmap[:len(test.exp)], test.exp) {
t.Fatalf("test %#v expected %x, got %x", i, test.exp, c.bitmap[:len(test.bitmap)])
}
if test.expN != c.n {
t.Fatalf("test #%v expected n to be %v, but got %v", i, test.expN, c.n)
}
}
}
func TestXorBitmapRun(t *testing.T) {
a := &container{}
b := &container{}
tests := []struct {
bitmap []uint64
runs []interval32
exp []uint64
}{
{bitmap: []uint64{0x0, 0x0, 0x0},
runs: []interval32{{start: 129, last: 131}},
exp: []uint64{0x0, 0x0, 0x00000000000000E},
},
}
for i, test := range tests {
a.bitmap = test.bitmap
b.runs = test.runs
ret := xorBitmapRun(a, b)
if !reflect.DeepEqual(ret.bitmap, test.exp) {
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.bitmap)
}
}
}