From 8041785ea4e3fabc52d14047568cb77e3743d371 Mon Sep 17 00:00:00 2001 From: Seebs Date: Tue, 19 Mar 2019 22:23:19 -0500 Subject: [PATCH] clean up some leftover bits from previous implementation It used to be useful/desireable to set the other slices to nil when setting a new slice type, it's no longer useful, take some of those out. Also reuse the already-computed run count when converting arrays and bitmaps to runs. --- roaring/roaring.go | 44 ++++++++++++++++++-------------- roaring/roaring_internal_test.go | 12 ++++----- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index 836fb307b..fb3fd5db6 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -1683,7 +1683,7 @@ func (c *Container) optimize() { c.arrayToBitmap() } else if newType == containerRun { statsHit("optimize/arrayToRun") - c.arrayToRun() + c.arrayToRun(runs) } else { statsHit("optimize/arrayUnchanged") } @@ -1693,7 +1693,7 @@ func (c *Container) optimize() { c.bitmapToArray() } else if newType == containerRun { statsHit("optimize/bitmapToRun") - c.bitmapToRun() + c.bitmapToRun(runs) } else { statsHit("optimize/bitmapUnchanged") } @@ -1899,17 +1899,16 @@ func (c *Container) bitmapToArray() { bitmap := c.bitmap() c.setBitmap(nil) c.typ = containerArray - array := make([]uint16, c.n) - c.setArray(array) - array = c.array() c.mapped = false // return early if empty if c.n == 0 { + c.setArray(nil) return } n := int32(0) + array := make([]uint16, c.n) for i, word := range bitmap { for word != 0 { t := word & -word @@ -1928,13 +1927,13 @@ func (c *Container) bitmapToArray() { panic("bitmap has fewer bits set than container.n") } } + c.setArray(array) } // arrayToBitmap converts from array format to bitmap format. func (c *Container) arrayToBitmap() { statsHit("arrayToBitmap") array := c.array() - c.setArray(nil) c.typ = containerBitmap bitmap := make([]uint64, bitmapN) c.setBitmap(bitmap) @@ -1954,7 +1953,6 @@ func (c *Container) arrayToBitmap() { func (c *Container) runToBitmap() { statsHit("runToBitmap") runs := c.runs() - c.setRuns(nil) bitmap := make([]uint64, bitmapN) c.typ = containerBitmap c.setBitmap(bitmap) @@ -1976,19 +1974,20 @@ func (c *Container) runToBitmap() { } // bitmapToRun converts from bitmap format to RLE format. -func (c *Container) bitmapToRun() { +func (c *Container) bitmapToRun(numRuns int32) { statsHit("bitmapToRun") bitmap := c.bitmap() - c.setBitmap(nil) c.mapped = false c.typ = containerRun // return early if empty if c.n == 0 { - c.setRuns(make([]interval16, 0)) + c.setRuns(nil) return } + if numRuns == 0 { + numRuns = bitmapCountRuns(bitmap) + } - numRuns := bitmapCountRuns(bitmap) runs := make([]interval16, 0, numRuns) current := bitmap[0] @@ -2032,19 +2031,20 @@ func (c *Container) bitmapToRun() { } // arrayToRun converts from array format to RLE format. -func (c *Container) arrayToRun() { +func (c *Container) arrayToRun(numRuns int32) { statsHit("arrayToRun") array := c.array() - c.setArray(nil) c.typ = containerRun c.mapped = false // return early if empty if c.n == 0 { - c.setRuns(make([]interval16, 0)) + c.setRuns(nil) return } + if numRuns == 0 { + numRuns = arrayCountRuns(array) + } - numRuns := arrayCountRuns(array) runs := make([]interval16, 0, numRuns) start := array[0] for i, v := range array[1:] { @@ -2062,21 +2062,27 @@ func (c *Container) arrayToRun() { // runToArray converts from RLE format to array format. func (c *Container) runToArray() { statsHit("runToArray") - array := make([]uint16, 0, c.n) runs := c.runs() - c.setRuns(nil) c.typ = containerArray c.mapped = false // return early if empty if c.n == 0 { - c.setArray(array) + c.setArray(nil) return } + array := make([]uint16, c.n) + n := int32(0) for _, r := range runs { for v := int(r.start); v <= int(r.last); v++ { - array = append(array, uint16(v)) + array[n] = uint16(v) + n++ + } + } + if roaringParanoia { + if n != c.n { + panic("run has fewer bits set than container.n") } } c.setArray(array) diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index 2935e43ac..e88356a37 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -244,12 +244,12 @@ func TestIntersectionCountArrayBitmap3(t *testing.T) { t.Fatalf("test #1 intersectCountBitmapBitmap fail orig: %v new: %v exp: %v", res.n, res.count(), maxContainerVal+1) } - a.bitmapToRun() + a.bitmapToRun(0) res = intersectBitmapRun(b, a) if res.n != res.count() || res.n != maxContainerVal+1 { t.Fatalf("test #2 intersectCountBitmapRun fail orig: %v new: %v exp: %v", res.n, res.count(), maxContainerVal+1) } - b.bitmapToRun() + b.bitmapToRun(0) res = intersectRunRun(a, b) n := intersectionCountRunRun(a, b) if res.n != res.count() || res.n != maxContainerVal+1 || res.n != int32(n) { @@ -1125,7 +1125,7 @@ func TestBitmapToRun(t *testing.T) { } a.n = int32(n) x := bitmap - a.bitmapToRun() + a.bitmapToRun(0) if !reflect.DeepEqual(a.runs(), test.exp) { t.Fatalf("test #%v expected %v, but got %v", i, test.exp, a.runs()) } @@ -1164,7 +1164,7 @@ func TestArrayToRun(t *testing.T) { a.typ = containerArray a.setArray(test.array) a.n = int32(len(test.array)) - a.arrayToRun() + a.arrayToRun(0) if !reflect.DeepEqual(a.runs(), test.exp) { t.Fatalf("test #%v expected %v, but got %v", i, test.exp, a.runs()) } @@ -3289,9 +3289,9 @@ func TestContainerCombinations(t *testing.T) { } } else if ct == containerRun { if clone.isArray() { - clone.arrayToRun() + clone.arrayToRun(0) } else if clone.isBitmap() { - clone.bitmapToRun() + clone.bitmapToRun(0) } if clone.n != cts[ct][exp].n { t.Fatalf("test %s expected runs n=%d, but got n=%d", desc, cts[ct][exp].n, clone.n)