diff --git a/roaring/roaring.go b/roaring/roaring.go index 80dbfa79a..49357620b 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -929,7 +929,7 @@ func (itr *Iterator) Next() (v uint64, eof bool) { itr.j++ // Find first non-zero bit in current bitmap, if possible. - hb := int(itr.j / 64) + hb := int(itr.j >> 6) if hb >= len(c.bitmap) { itr.i, itr.j = itr.i+1, -1 @@ -944,7 +944,7 @@ func (itr *Iterator) Next() (v uint64, eof bool) { // Otherwise iterate through remaining bitmaps to find next bit. for hb++; hb < len(c.bitmap); hb++ { if c.bitmap[hb] != 0 { - itr.j = int(hb*64) + trailingZeroN(c.bitmap[hb]) + itr.j = int(hb<<6) + trailingZeroN(c.bitmap[hb]) return itr.peek(), false } } @@ -1909,7 +1909,7 @@ func intersectionCountArrayBitmapOld(a, b *container) (n uint64) { func intersectionCountArrayBitmap(a, b *container) (n uint64) { for _, val := range a.array { - i := val / 64 + i := val >> 6 if i >= uint32(len(b.bitmap)) { break } @@ -2052,8 +2052,8 @@ func intersectBitmapRun(a, b *container) *container { } for j := 0; j < len(b.runs); j++ { vb := b.runs[j] - i := vb.start / 64 // index into a - vastart := 64 * i + i := vb.start >> 6 // index into a + vastart := i << 6 valast := vastart + 63 for valast >= vb.start && vastart <= vb.last { if vastart >= vb.start && valast <= vb.last { // a within b @@ -2077,7 +2077,7 @@ func intersectBitmapRun(a, b *container) *container { } // update loop vars i++ - vastart = 64 * i + vastart = i << 6 valast = vastart + 63 } } @@ -2300,8 +2300,8 @@ const maxBitmap = 0xFFFFFFFFFFFFFFFF // sets all bits in [i, j) (c must be a bitmap container) func (c *container) bitmapSetRange(i, j uint64) { - x := i / 64 - y := (j - 1) / 64 + x := i >> 6 + y := (j - 1) >> 6 var X uint64 = maxBitmap << (i % 64) var Y uint64 = maxBitmap >> (64 - (j % 64)) xcnt := popcnt(X) @@ -2323,8 +2323,8 @@ func (c *container) bitmapSetRange(i, j uint64) { // xor's all bits in [i, j) with all true (c must be a bitmap container). func (c *container) bitmapXorRange(i, j uint64) { - x := i / 64 - y := (j - 1) / 64 + x := i >> 6 + y := (j - 1) >> 6 var X uint64 = maxBitmap << (i % 64) var Y uint64 = maxBitmap >> (64 - (j % 64)) if x == y { @@ -2348,8 +2348,8 @@ func (c *container) bitmapXorRange(i, j uint64) { // zeroes all bits in [i, j) (c must be a bitmap container) func (c *container) bitmapZeroRange(i, j uint64) { - x := i / 64 - y := (j - 1) / 64 + x := i >> 6 + y := (j - 1) >> 6 var X uint64 = maxBitmap << (i % 64) var Y uint64 = maxBitmap >> (64 - (j % 64)) if x == y { diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index 291036ef8..0b103ae5f 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -1929,3 +1929,32 @@ func TestRunBinSearch(t *testing.T) { } } } +func TestBitmap_RemoveEmptyContainers(t *testing.T) { + bm1 := NewBitmap(1<<16, 2<<16, 3<<16) + bm1.Remove(2 << 16) + if bm1.countEmptyContainers() != 1 { + t.Fatalf("Should be 1 empty container ") + } + bm1.removeEmptyContainers() + + if bm1.countEmptyContainers() != 0 { + t.Fatalf("Should be no empty containers ") + } +} + +func TestBitmap_BitmapWriteToWithEmpty(t *testing.T) { + bm1 := NewBitmap(1<<16, 2<<16, 3<<16) + bm1.Remove(2 << 16) + var buf bytes.Buffer + if _, err := bm1.WriteTo(&buf); err != nil { + t.Fatalf("Failure to write to bitmap buffer. ") + } + bm0 := NewBitmap() + bm0.UnmarshalBinary(buf.Bytes()) + if bm0.countEmptyContainers() != 0 { + t.Fatalf("Should be no empty containers ") + } + if bm0.Count() != bm1.Count() { + t.Fatalf("Counts do not match after a marshal %d %d", bm0.Count(), bm1.Count()) + } +} diff --git a/roaring/roaring_test.go b/roaring/roaring_test.go index 8150f4376..ba24ecd22 100644 --- a/roaring/roaring_test.go +++ b/roaring/roaring_test.go @@ -15,8 +15,8 @@ package roaring_test import ( - "fmt" "bytes" + "fmt" "math" "math/rand" "reflect" @@ -166,7 +166,6 @@ func TestBitmap_CountRange(t *testing.T) { if n := bm0.CountRange(0, 1); n != 1 { t.Fatalf("unexpected n: %d", n) } - } func TestBitmap_Intersection(t *testing.T) { @@ -418,6 +417,21 @@ func TestBitmap_IntersectionCount_BitmapBitmap(t *testing.T) { t.Fatalf("unexpected n (reverse): %d", n) } } +func TestBitmap_IntersectionCount_Mixed(t *testing.T) { + bm0 := testBM() + bm1 := roaring.NewBitmap(0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 65536) + bm3 := roaring.NewBitmap(131072) + + if n := bm0.IntersectionCount(bm0); n != bm0.Count() { + t.Fatalf("unexpected n: %d", n) + } + if n := bm0.IntersectionCount(bm1); n != 1 { + t.Fatalf("unexpected n: %d", n) + } + if n := bm0.IntersectionCount(bm3); n != 1 { + t.Fatalf("unexpected n: %d", n) + } +} func TestBitmap_Quick_Array1(t *testing.T) { testBitmapQuick(t, 1000, 1000, 2000) } func TestBitmap_Quick_Array2(t *testing.T) { testBitmapQuick(t, 10000, 0, 1000) } @@ -585,6 +599,42 @@ func TestIterator(t *testing.T) { } } +//testBM creates a bitmap with 3 containers(an array,bitmap, and run) +func testBM() *roaring.Bitmap { + bm := roaring.NewBitmap() + //the array + for i := uint64(0); i < 1024; i += 4 { + bm.Add((1 << 16) + i) + } + //the bitmap + for i := uint64(0); i < 16384; i += 2 { + bm.Add((2 << 16) + i) + } + //small run + for i := uint64(0); i < 1024; i += 1 { + bm.Add((3 << 16) + i) + } + //large run + for i := uint64(0); i < 65535; i += 1 { + bm.Add((4 << 16) + i) + } + return bm +} + +func TestBitmapOffsetRange(t *testing.T) { + bm := testBM() + + bm1 := bm.OffsetRange(0, 0, 327680) + if bm1.Count() != bm.Count() { + t.Fatalf("Not Equal %d %d", bm1.Count(), bm.Count()) + } + bm1 = bm.OffsetRange(0, 0, 131072) + if bm1.Count() != 256 { + t.Fatalf("Not Equal %d %d", bm1.Count(), 256) + } + +} + var benchmarkBitmapIntersectionCountData struct { a, b *roaring.Bitmap }