From d4e496887b49e326db467f547420a4aad0ed5569 Mon Sep 17 00:00:00 2001 From: Seebs Date: Thu, 2 Apr 2020 15:33:52 -0500 Subject: [PATCH] make differenceRunBitmap smarter We avoid using bitmapContains so often because that turns out to be expensive. Also, if we produce more than runMaxSize runs, we're going to convert to a bitmap container (or possibly an array container if there were over 2048 items, but they're all singletons), and we can streamline that by just converting the source to bitmap and returning differenceBitmapBitmap, which is faster in this case. This appears to overall take about half as long in the workload I was looking at. --- roaring/roaring.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index c399b8df6..10b49e2b8 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -4335,12 +4335,14 @@ func differenceRunBitmap(a, b *Container) *Container { if len(ra) > 0 && ra[0].start == 0 && ra[0].last == 65535 { return flipBitmap(b) } + bb := b.bitmap()[:1024] runs := make([]interval16, 0, len(ra)) for _, inputRun := range ra { run := inputRun add := true for bit := inputRun.start; bit <= inputRun.last; bit++ { - if b.bitmapContains(bit) { + idx, exp := int(bit>>6), bit&63 + if (bb[idx]>>exp)&1 != 0 { if run.start == bit { if bit == 65535 { //overflow add = false @@ -4352,6 +4354,10 @@ func differenceRunBitmap(a, b *Container) *Container { } else { run.last = bit - 1 if run.last >= run.start { + if len(runs) >= runMaxSize { + asBitmap := a.runToBitmap() + return differenceBitmapBitmap(asBitmap, b) + } runs = append(runs, run) } run.start = bit + 1 @@ -4368,6 +4374,10 @@ func differenceRunBitmap(a, b *Container) *Container { } if run.start <= run.last { if add { + if len(runs) >= runMaxSize { + asBitmap := a.runToBitmap() + return differenceBitmapBitmap(asBitmap, b) + } runs = append(runs, run) } }