Add implementations and minimal tests for bitmap-run conversions

This commit is contained in:
Alan Bernstein 2017-06-01 10:54:22 -05:00 • committed by Matt Jaffee
parent ac5f776db9
commit bff12f5ce1
2 changed files with 124 additions and 2 deletions

View file

@ -1363,12 +1363,65 @@ func (c *container) arrayToBitmap() {
c.mapped = false
}
// runToBitmap converts from RLE format to bitmap format
func (c *container) runToBitmap() {
// TODO
c.bitmap = make([]uint64, bitmapN)
for _, r := range c.runs {
// TODO is there a faster way ?!?!!
for v := r.start; v <= r.last; v++ {
c.bitmap[int(v)/64] |= (uint64(1) << uint(v%64))
}
}
c.runs = nil
c.mapped = false
}
// bitmapToRun converts from bitmap format to RLE format
func (c *container) bitmapToRun() {
// TODO
numRuns := c.n // TODO compute properly
c.runs = make([]interval32, 0, numRuns)
// TODO return early if no runs
current := c.bitmap[0]
var i, start, last uint32
for {
// skip while empty
for current == 0 && i < bitmapN-1 {
i++
current = c.bitmap[i]
}
if current == 0 {
break
}
currentStart := uint32(trailingZeroN(current))
start = 64 * i + currentStart
// pad LSBs with 1s
current = current | (current-1)
// find next 0
for current == 0xFFFFFFFFFFFFFFFF && i < bitmapN-1 {
i++
current = c.bitmap[i]
}
last = 0
if current == 0xFFFFFFFFFFFFFFFF {
last = 64*i + 64 // TODO verify
c.runs = append(c.runs, interval32{start, last-1})
break
}
currentLast := uint32(trailingZeroN(^current))
last = 64 * i + currentLast
c.runs = append(c.runs, interval32{start, last-1})
// pad LSBs with 0s
current = current & (current+1)
}
c.bitmap = nil
c.mapped = false
}
// arrayToRun converts from array format to RLE format

View file

@ -731,6 +731,75 @@ func TestBitmapSetRange(t *testing.T) {
}
}
func TestRunToBitmap(t *testing.T) {
a := &container{}
tests := []struct {
runs []interval32
exp []uint64
}{
{
runs: []interval32{{start: 0, last: 0}},
exp: []uint64{1},
},
{
runs: []interval32{{start: 0, last: 4}},
exp: []uint64{31},
},
{
runs: []interval32{{start: 2, last: 2}, {start: 5, last: 7}, {start: 13, last: 14}, {start: 17, last: 17}},
exp: []uint64{155876},
},
}
for i, test := range tests {
exp := make([]uint64, bitmapN)
for i, v := range test.exp {
exp[i] = v
}
a.runs = test.runs
a.runToBitmap()
if !reflect.DeepEqual(a.bitmap, exp) {
t.Logf("test #%v expected %v, but got (%d) %v", i, exp, a.bitmap)
}
}
}
func TestBitmapToRun(t *testing.T) {
a := &container{}
tests := []struct {
bitmap []uint64
exp []interval32
}{
{
bitmap: []uint64{1},
exp: []interval32{{start: 0, last: 0}},
},
{
bitmap: []uint64{31},
exp: []interval32{{start: 0, last: 4}},
},
{
bitmap: []uint64{155876},
exp: []interval32{{start: 2, last: 2}, {start: 5, last: 7}, {start: 13, last: 14}, {start: 17, last: 17}},
},
}
for i, test := range tests {
a.bitmap = make([]uint64, bitmapN)
n := 0
for i, v := range test.bitmap {
a.bitmap[i] = v
n += int(popcount(v))
}
a.n = n
a.bitmapToRun()
if !reflect.DeepEqual(a.runs, test.exp) {
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, a.runs)
}
}
}
func TestArrayToRun(t *testing.T) {
a := &container{}
tests := []struct {