diff --git a/roaring/roaring.go b/roaring/roaring.go index 3dc643f2c..310ab78cb 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -1329,17 +1329,17 @@ func (c *container) bitmapToRun() { // arrayToRun converts from array format to RLE format func (c *container) arrayToRun() { - c.runs = make([]interval32, 0) + c.runs = make([]interval32, 0, c.n) // what capacity to use? start := c.array[0] - for i, v := range c.array { - if v - c.array[i-1] > 1 { + for i, v := range c.array[1:] { + if v - c.array[i] > 1 { // if current-previous > 1, one run ends and another begins - c.runs = append(c.runs, interval32{start, c.array[i-1]}) + c.runs = append(c.runs, interval32{start, c.array[i]}) start = v } } // append final run - c.runs = append(c.runs, interval32{start, c.array[i]}) + c.runs = append(c.runs, interval32{start, c.array[c.n-1]}) c.array = nil c.mapped = false } diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index 186e014bd..4424969ad 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -731,6 +731,36 @@ func TestBitmapSetRange(t *testing.T) { } } +func TestArrayToRun(t *testing.T) { + a := &container{} + tests := []struct { + array []uint32 + exp []interval32 + }{ + { + array: []uint32{0}, + exp: []interval32{{start: 0, last: 0}}, + }, + { + array: []uint32{0, 1, 2, 3, 4}, + exp: []interval32{{start: 0, last: 4}}, + }, + { + array: []uint32{2, 5, 6, 7, 13, 14, 17}, + exp: []interval32{{start: 2, last: 2}, {start: 5, last: 7}, {start: 13, last: 14}, {start: 17, last: 17}}, + }, + } + + for i, test := range tests { + a.array = test.array + a.n = len(test.array) + a.arrayToRun() + if !reflect.DeepEqual(a.runs, test.exp) { + t.Fatalf("test #%v expected %v, but got %v", i, test.exp, a.runs) + } + } +} + func TestBitmapZeroRange(t *testing.T) { c := &container{bitmap: make([]uint64, bitmapN)} tests := []struct { @@ -811,5 +841,34 @@ func TestUnionBitmapRun(t *testing.T) { a.bitmap[i] = 0 } } - +} + +func TestRunToArray(t *testing.T) { + a := &container{} + tests := []struct { + runs []interval32 + exp []uint32 + }{ + { + runs: []interval32{{start: 0, last: 0}}, + exp: []uint32{0}, + }, + { + runs: []interval32{{start: 0, last: 4}}, + exp: []uint32{0, 1, 2, 3, 4}, + }, + { + runs: []interval32{{start: 2, last: 2}, {start: 5, last: 7}, {start: 13, last: 14}, {start: 17, last: 17}}, + exp: []uint32{2, 5, 6, 7, 13, 14, 17}, + }, + } + + for i, test := range tests { + a.runs = test.runs + a.n = len(test.exp) + a.runToArray() + if !reflect.DeepEqual(a.array, test.exp) { + t.Fatalf("test #%v expected %v, but got %v", i, test.exp, a.array) + } + } }