diff --git a/roaring/roaring.go b/roaring/roaring.go index 0087e6fdf..2a8b6645c 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -1674,19 +1674,6 @@ 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), containerType: 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() { @@ -1812,6 +1799,43 @@ type ContainerInfo struct { Pointer unsafe.Pointer // offset within the mmap } +// flip returns a new container containing the inverse of all +// bits in a. +func flip(a *container) *container { + if a.isArray() { + return flipArray(a) + } else if a.isRun() { + return flipRun(a) + } else { + return flipBitmap(a) + } +} + +func flipArray(b *container) *container { + // TODO: actually implement this + x := b.clone() + x.arrayToBitmap() + return flipBitmap(x) +} + +func flipBitmap(b *container) *container { + other := &container{bitmap: make([]uint64, bitmapN), containerType: ContainerBitmap} + + for i, bitmap := range b.bitmap { + other.bitmap[i] = ^bitmap + } + + other.n = other.count() + return other +} + +func flipRun(b *container) *container { + // TODO: actually implement this + x := b.clone() + x.runToBitmap() + return flipBitmap(x) +} + func intersectionCount(a, b *container) int { if a.isArray() { if b.isArray() { @@ -2571,7 +2595,7 @@ RUNLOOP: func differenceRunBitmap(a, b *container) *container { // If a is full, difference is the flip of b. if len(a.runs) > 0 && a.runs[0].start == 0 && a.runs[0].last == 65535 { - return b.flipBitmap() + return flipBitmap(b) } output := &container{containerType: ContainerRun} output.n = a.n diff --git a/roaring/roaring_helpers_test.go b/roaring/roaring_helpers_test.go index ea6d86cd9..417ac7db6 100644 --- a/roaring/roaring_helpers_test.go +++ b/roaring/roaring_helpers_test.go @@ -220,8 +220,11 @@ func runEvenBitsSet() []interval16 { /////////////////////////////////////////////////////////////////////////// +// f is a container function taking either one or two containers as input +// func(a *container) *container +// func(a, b *container) *container type testOp struct { - f func(a, b *container) *container + f interface{} x string y string exp string diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index dca413811..216aa7eb7 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -2020,38 +2020,6 @@ func TestXorRunRun(t *testing.T) { } } -func TestBitmapFlip(t *testing.T) { - c := &container{bitmap: make([]uint64, bitmapN), containerType: 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), containerType: ContainerBitmap} tests := []struct { @@ -3185,12 +3153,24 @@ func TestContainerCombinations(t *testing.T) { //{xor, "evenBitsSet", "outerBitsSet", ""}, {xor, "evenBitsSet", "oddBitsSet", "full"}, {xor, "evenBitsSet", "evenBitsSet", "empty"}, + + // flip + {flip, "empty", "", "full"}, + {flip, "full", "", "empty"}, + {flip, "firstBitSet", "", "firstBitUnset"}, + {flip, "lastBitSet", "", "lastBitUnset"}, + {flip, "firstBitUnset", "", "firstBitSet"}, + {flip, "lastBitUnset", "", "lastBitSet"}, + {flip, "innerBitsSet", "", "outerBitsSet"}, + {flip, "outerBitsSet", "", "innerBitsSet"}, + {flip, "oddBitsSet", "", "evenBitsSet"}, + {flip, "evenBitsSet", "", "oddBitsSet"}, } for _, testOp := range testOps { for _, x := range containerTypes { for _, y := range containerTypes { desc := fmt.Sprintf("%s(%s/%s, %s/%s)", getFunctionName(testOp.f), cm[x], testOp.x, cm[y], testOp.y) - ret := testOp.f(cts[x][testOp.x], cts[y][testOp.y]) + ret := runContainerFunc(testOp.f, cts[x][testOp.x], cts[y][testOp.y]) exp := testOp.exp // Convert to all container types and check result. @@ -3240,3 +3220,14 @@ func TestContainerCombinations(t *testing.T) { } } } + +//func getFunc(func(a, b *container) *container, m, n *container) *container { +func runContainerFunc(f interface{}, c ...*container) *container { + switch f.(type) { + case func(*container) *container: + return f.(func(*container) *container)(c[0]) + case func(*container, *container) *container: + return f.(func(a, b *container) *container)(c[0], c[1]) + } + return nil +}