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.
This commit is contained in:
Seebs 2020-04-02 15:33:52 -05:00
parent 7868188670
commit d4e496887b

View file

@ -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)
}
}