While looking at benchmarks as a possible go compiler benchmarks.
I've tried some optimizations by hand:
Move len(b.bitmap) load out of the loop.
Remove some type conversions.
Use (x >> off) & 1 to get offs bit, instead of x & (1 << of)f >> off.
This produces nice speed-up and passes go test roaring.
name old time/op new time/op delta
Bitmap_IntersectionCount_ArrayRun-6 2.06µs ± 0% 1.57µs ± 0% -24.04% (p=0.000 n=10+9)
Bitmap_IntersectionCount_BitmapRun-6 2.24µs ± 0% 2.24µs ± 0% ~ (p=0.913 n=10+9)
Bitmap_IntersectionCount_ArrayBitmap-6 2.06µs ± 0% 1.56µs ± 1% -24.05% (p=0.000 n=9+10)
There was a case where the Bitmap iterator logic could skip over a bit in a run
container if 1. the run container was not the first container in the bitmap, and
2. The first run in the run container had only one bit.
The bug was due to how the iterator was initialized with iterator.Seek(0) which
sets up the initial values of itr.i,j,k based on the type of the first
container. It was failing to set itr.k to -1 unless the first container was an
RLE container. itr.k is only used by RLE containers in the iterator, and must be
set to -1 when an RLE container is encountered. When Iterator.Next() encountered
the run container and itr.k was set to 0, it checked to see if itr.k <= run.last
- run.first, and if so it assumes that it was finished with the run and moved to
the next one. run.last - run.first is 0 in the case of a single bit run, so that
bit was skipped. After this, itr.k is set to -1 and all further iteration
proceeds as expected.
When the difference of two run containers resulted in an empty
container, that container would be a run container with no runs.
The Iterator was expected there to be at least on run in
`container.runs`. This fix protects against that and adds tests
for that case.