diff --git a/roaring/roaring.go b/roaring/roaring.go index 85721468a..57895b4e3 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -2531,15 +2531,46 @@ func differenceRunArray(a, b *container) *container { // differenceRunBitmap computes the difference of an run from a bitmap. func differenceRunBitmap(a, b *container) *container { - if a.n == 0 || b.n == 0 { - return a.clone() - } // If a is full, difference is the flip of b. if a.runs[0].start == 0 && a.runs[0].last == 65535 { return b.flipBitmap() } - itr := newBufBitmapIterator(newBitmapIterator(b.bitmap)) - return differenceRunIterator(a, itr) + output := &container{container_type: ContainerRun} + output.n = a.n + for j := 0; j < len(a.runs); j++ { + run := a.runs[j] + for bit := a.runs[j].start; bit <= a.runs[j].last; bit++ { + if b.bitmapContains(bit) { + output.n-- + if run.start == bit { + run.start++ + } else if bit == run.last { + run.last-- + } else { + run.last = bit - 1 + if run.last >= run.start { + output.runs = append(output.runs, run) + } + run.start = bit + 1 + run.last = a.runs[j].last + } + if run.start > run.last { + break + } + } + } + if run.start <= run.last { + output.runs = append(output.runs, run) + + } + } + + if output.n < ArrayMaxSize && int(len(output.runs)) > output.n/2 { + output.runToArray() + } else if len(output.runs) > RunMaxSize { + output.runToBitmap() + } + return output } func differenceRunIterator(a *container, itr containerIterator) *container { diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index e711fecc8..07f30888b 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -1464,6 +1464,15 @@ func TestDifferenceRunArray(t *testing.T) { } } } +func MakeBitmap(start []uint64) []uint64 { + + b := make([]uint64, bitmapN) + for i, v := range start { + b[i] = v + + } + return b +} func TestDifferenceRunBitmap(t *testing.T) { a := &container{} @@ -1475,32 +1484,32 @@ func TestDifferenceRunBitmap(t *testing.T) { }{ { runs: []interval16{{start: 0, last: 63}}, - bitmap: []uint64{0x0000FFFF000000F0}, + bitmap: MakeBitmap([]uint64{0x0000FFFF000000F0}), exp: []interval16{{start: 0, last: 3}, {start: 8, last: 31}, {start: 48, last: 63}}, }, { runs: []interval16{{start: 0, last: 63}}, - bitmap: []uint64{0x8000000000000000}, + bitmap: MakeBitmap([]uint64{0x8000000000000000}), exp: []interval16{{start: 0, last: 62}}, }, { runs: []interval16{{start: 0, last: 63}}, - bitmap: []uint64{0x0000000000000001}, + bitmap: MakeBitmap([]uint64{0x0000000000000001}), exp: []interval16{{start: 1, last: 63}}, }, { runs: []interval16{{start: 0, last: 63}}, - bitmap: []uint64{0x0, 0x0000000000000001}, + bitmap: MakeBitmap([]uint64{0x0, 0x0000000000000001}), exp: []interval16{{start: 0, last: 63}}, }, { runs: []interval16{{start: 0, last: 65}}, - bitmap: []uint64{0x0, 0x0000000000000001}, + bitmap: MakeBitmap([]uint64{0x0, 0x0000000000000001}), exp: []interval16{{start: 0, last: 63}, {start: 65, last: 65}}, }, { runs: []interval16{{start: 0, last: 65}}, - bitmap: []uint64{0x0, 0x8000000000000000}, + bitmap: MakeBitmap([]uint64{0x0, 0x8000000000000000}), exp: []interval16{{start: 0, last: 65}}, }, }