From a3f3ca3c5abc25a8dd10099af4d4fd138a308ae0 Mon Sep 17 00:00:00 2001 From: Todd Gruben Date: Tue, 1 Aug 2017 16:25:11 -0500 Subject: [PATCH] fixed overflow in interval16 runlen; added rle tests --- roaring/roaring.go | 9 +++++---- roaring/roaring_internal_test.go | 18 ++++++++++++++++++ roaring/roaring_test.go | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index d7ae9b6d3..57aa41e96 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -948,7 +948,7 @@ type interval16 struct { // runlen returns the count of integers in the interval. func (iv interval16) runlen() int { - return int(1 + iv.last - iv.start) + return 1 + int(iv.last-iv.start) } // newContainer returns a new instance of container. @@ -958,17 +958,17 @@ func newContainer() *container { // isArray returns true if the container is an array container. func (c *container) isArray() bool { - return c.bitmap == nil && c.runs == nil + return c.container_type == ContainerArray } // isBitmap returns true if the container is a bitmap container. func (c *container) isBitmap() bool { - return c.array == nil && c.runs == nil + return c.container_type == ContainerBitmap } // isRun returns true if the container is a run-length-encoded container. func (c *container) isRun() bool { - return c.array == nil && c.bitmap == nil + return c.container_type == ContainerRun } // unmap creates copies of the containers data in the heap. @@ -1507,6 +1507,7 @@ func (c *container) bitmapToRun() { } if current == maxBitmap { + // bitmap[1023] == maxBitmap c.runs = append(c.runs, interval16{start, maxContainerVal}) break diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index f1e64068e..f9540d943 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -1022,6 +1022,15 @@ func TestRunToBitmap(t *testing.T) { } } +func getFullBitmap() []uint64 { + x := make([]uint64, 1024, 1024) + for i := range x { + x[i] = uint64(0xFFFFFFFFFFFFFFFF) + } + return x + +} + func TestBitmapToRun(t *testing.T) { a := &container{} tests := []struct { @@ -1072,6 +1081,10 @@ func TestBitmapToRun(t *testing.T) { bitmap: make([]uint64, bitmapN), exp: []interval16{{start: 65408, last: 65535}}, }, + { + bitmap: getFullBitmap(), + exp: []interval16{{start: 0, last: 65535}}, + }, } tests[8].bitmap[1022] = 0xFFFFFFFFFFFFFFFF tests[8].bitmap[1023] = 0xFFFFFFFFFFFFFFFF @@ -1084,10 +1097,15 @@ func TestBitmapToRun(t *testing.T) { n += int(popcount(v)) } a.n = n + x := a.bitmap a.bitmapToRun() if !reflect.DeepEqual(a.runs, test.exp) { t.Fatalf("test #%v expected %v, but got %v", i, test.exp, a.runs) } + a.runToBitmap() + if !reflect.DeepEqual(a.bitmap, x) { + t.Fatalf("test #%v expected %v, but got %v", i, a.bitmap, x) + } } } diff --git a/roaring/roaring_test.go b/roaring/roaring_test.go index 05857465a..8de92eb4e 100644 --- a/roaring/roaring_test.go +++ b/roaring/roaring_test.go @@ -87,6 +87,24 @@ func TestCheckRun(t *testing.T) { t.Fatalf("%v\n", err) } } +func TestCheckFullRun(t *testing.T) { + b := roaring.NewBitmap() + for i := uint64(0); i < 2097152; i++ { + if i%16384 == 0 { + b.Optimize() // convert to runs + } + b.Add(i) + } + err := b.Check() + if err != nil { + t.Fatalf("Before %v\n", err) + } + b.Optimize() // convert to runs + err = b.Check() + if err != nil { + t.Fatalf("After %v\n", err) + } +} // Ensure that we can transition between runs and arrays when materializing the bitmap. func TestContainerTransitions(t *testing.T) {