From 0d4f634dd86e6f04eeeae08b35750a15d0696d38 Mon Sep 17 00:00:00 2001 From: Travis Date: Wed, 20 Sep 2017 13:04:52 -0500 Subject: [PATCH] implement container.flipBitmap() to improve differenceRunBitmap() --- roaring/roaring.go | 19 ++++++++++++++++++- roaring/roaring_internal_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index f54efb76f..602fb9c8b 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -965,7 +965,7 @@ const RunMaxSize = 2048 // an array or RLE container is used, depending on the contents. For containers // with more than 4,096 values, the values are encoded into bitmaps. type container struct { - container_type byte // number of integers in container + container_type byte // array, bitmap, or run n int // number of integers in container array []uint16 // used for array containers bitmap []uint64 // used for bitmap containers @@ -1625,6 +1625,19 @@ func (c *container) clone() *container { return other } +// flipBitmap returns a new bitmap containter containing the inverse of all +// bits in c. +func (c *container) flipBitmap() *container { + other := &container{bitmap: make([]uint64, bitmapN), container_type: ContainerBitmap} + + for i, bitmap := range c.bitmap { + other.bitmap[i] = ^bitmap + } + + other.n = other.count() + return other +} + // WriteTo writes c to w. func (c *container) WriteTo(w io.Writer) (n int64, err error) { if c.isArray() { @@ -2533,6 +2546,10 @@ 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) } diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index 5d1a985d1..9339e6df9 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -1869,6 +1869,38 @@ func TestXorRunRun(t *testing.T) { } } +func TestBitmapFlip(t *testing.T) { + c := &container{bitmap: make([]uint64, bitmapN), container_type: ContainerBitmap} + + ttable := []struct { + original uint64 + flipped uint64 + }{ + {0x0000000000000000, 0xFFFFFFFFFFFFFFFF}, + {0xFFFFFFFFFFFFFFFF, 0x0000000000000000}, + {0xFFFFFFFFFFFFFFF0, 0x000000000000000F}, + {0xFFFFFFEFFFFFFFFF, 0x0000001000000000}, + {0x0000001000000000, 0xFFFFFFEFFFFFFFFF}, + } + + expectedN := int(65536) + for i, tt := range ttable { + c.bitmap[i] = tt.original + expectedN -= int(popcount(tt.original)) + } + + o := c.flipBitmap() + + for i, tt := range ttable { + if o.bitmap[i] != tt.flipped { + t.Fatalf("bitmapFlip calculation. expected %v, got %v", tt.flipped, o.bitmap[i]) + } + } + if o.n != expectedN { + t.Fatalf("bitmapFlip calculation. expected count %v, got %v", expectedN, o.n) + } +} + func TestBitmapXorRange(t *testing.T) { c := &container{bitmap: make([]uint64, bitmapN), container_type: ContainerBitmap} tests := []struct {