From fd73eaa5cb51d489fa4bc0f4f93c149f9b188950 Mon Sep 17 00:00:00 2001 From: Matthew Jaffee Date: Fri, 22 Sep 2017 01:02:41 -0500 Subject: [PATCH] re-implement differenceRunArray to not use iterator hopefully less heap allocs and better perf now --- roaring/roaring.go | 43 +++++++++++++++++++++++++++++--- roaring/roaring_internal_test.go | 15 +++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index e10b6a99e..9eb927d79 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -2451,13 +2451,50 @@ func differenceBitmapRun(a, b *container) *container { return output } -// differenceRunArray computes the difference of an run from a array. +// differenceRunArray subtracts the bits in an array container from a run +// container. func differenceRunArray(a, b *container) *container { if a.n == 0 || b.n == 0 { return a.clone() } - itr := newArrayIterator(b.array) - return differenceRunIterator(a, itr) + output := &container{runs: make([]interval16, 0, len(a.runs)), container_type: ContainerRun} + + bidx := 0 + vb := b.array[bidx] + for _, run := range a.runs { + start := run.start + for vb < run.start { + bidx++ + if bidx >= len(b.array) { + break + } + vb = b.array[bidx] + } + for vb >= run.start && vb <= run.last { + if vb == start { + start++ + bidx++ + if bidx >= len(b.array) { + break + } + vb = b.array[bidx] + continue + } + output.runs = append(output.runs, interval16{start: start, last: vb - 1}) + start = vb + 1 + bidx++ + if bidx >= len(b.array) { + break + } + vb = b.array[bidx] + } + + if start <= run.last { + output.runs = append(output.runs, interval16{start: start, last: run.last}) + } + } + output.Optimize() + return output } // differenceRunBitmap computes the difference of an run from a bitmap. diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index 59318038c..0afa346d1 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -1449,6 +1449,21 @@ func TestDifferenceRunArray(t *testing.T) { array: []uint16{0, 9, 10, 11, 12, 13}, exp: []interval16{{start: 1, last: 8}}, }, + { + runs: []interval16{{start: 1, last: 12}, {start: 14, last: 14}, {start: 18, last: 18}}, + array: []uint16{0, 9, 10, 11, 12, 13, 14, 17}, + exp: []interval16{{start: 1, last: 8}, {start: 18, last: 18}}, + }, + { + runs: []interval16{{start: 1, last: 12}, {start: 14, last: 14}, {start: 18, last: 18}}, + array: []uint16{0, 9, 10, 11, 12, 13, 14, 17, 19}, + exp: []interval16{{start: 1, last: 8}, {start: 18, last: 18}}, + }, + { + runs: []interval16{{start: 1, last: 12}, {start: 14, last: 17}, {start: 19, last: 28}}, + array: []uint16{0, 9, 10, 11, 12, 13, 14, 17, 19, 25, 27}, + exp: []interval16{{start: 1, last: 8}, {start: 15, last: 16}, {start: 20, last: 24}, {start: 26, last: 26}, {start: 28, last: 28}}, + }, } for i, test := range tests { a.runs = test.runs