diff --git a/roaring/roaring.go b/roaring/roaring.go index 310ab78cb..7c64472e3 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -1164,6 +1164,27 @@ func (c *container) contains(v uint32) bool { } } +func (c *container) bitmapCountRuns() (r int) { + for i := 0; i < 1023; i++ { + v, v1 := c.bitmap[i], c.bitmap[i+1] + r = r + int(popcnt((v<<1)&^v)+((v>>63)&^v1)) + } + vl := c.bitmap[len(c.bitmap)-1] + r = r + int(popcnt((vl<<1)&^vl)+vl>>63) + return r +} + +func (c *container) arrayCountRuns() (r int) { + prev := -2 + for _, v := range c.array { + if uint32(prev+1) != v { + r += 1 + } + prev = int(v) + } + return r +} + func (c *container) arrayContains(v uint32) bool { return search32(c.array, v) >= 0 } diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index 4424969ad..1d58c9b01 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -872,3 +872,94 @@ func TestRunToArray(t *testing.T) { } } } + +func TestBitmapCountRuns(t *testing.T) { + c := &container{bitmap: make([]uint64, bitmapN)} + tests := []struct { + bitmap []uint64 + exp int + }{ + { + bitmap: []uint64{0xFF00FF00}, + exp: 2, + }, + { + bitmap: []uint64{0xFF00FF0000000000, 0x1}, + exp: 2, + }, + { + bitmap: []uint64{0xFF00FF0000000000, 0x2, 0x100}, + exp: 4, + }, + { + bitmap: []uint64{0xFF00FF0000000000, 0x1010101FF0101010, 0x100}, + exp: 10, + }, + } + + for i, test := range tests { + for j, v := range test.bitmap { + c.bitmap[j] = v + } + + ret := c.bitmapCountRuns() + if ret != test.exp { + t.Fatalf("test #%v expected %v but got %v", i, test.exp, ret) + } + + for j, _ := range test.bitmap { + c.bitmap[j] = 0 + } + } + + test := tests[3] + for j, v := range test.bitmap { + c.bitmap[1024-len(test.bitmap)+j] = v + + } + ret := c.bitmapCountRuns() + if ret != test.exp { + t.Fatalf("test at end expected %v but got %v", test.exp, ret) + } +} + +func TestArrayCountRuns(t *testing.T) { + c := &container{} + tests := []struct { + array []uint32 + exp int + }{ + { + array: []uint32{}, + exp: 0, + }, + { + array: []uint32{0}, + exp: 1, + }, + { + array: []uint32{1}, + exp: 1, + }, + { + array: []uint32{1, 2, 3, 5}, + exp: 2, + }, + { + array: []uint32{0, 1, 3, 9, 2048, 4096, 4097, 65534, 65535}, + exp: 6, + }, + { + array: []uint32{0, 10, 11, 12}, + exp: 2, + }, + } + + for i, test := range tests { + c.array = test.array + ret := c.arrayCountRuns() + if ret != test.exp { + t.Fatalf("test #%v expected %v but got %v", i, test.exp, ret) + } + } +}