mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-09 22:51:02 +00:00
included previous patterns for in place testing
This commit is contained in:
parent
0459285101
commit
f40ced47fa
3 changed files with 618 additions and 2 deletions
|
|
@ -25,6 +25,7 @@ import (
|
|||
"sort"
|
||||
"unsafe"
|
||||
|
||||
"github.com/pilosa/pilosa"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
|
@ -995,8 +996,6 @@ func (b *Bitmap) unionInPlace(others ...*Bitmap) {
|
|||
// Difference returns the difference of b and other.
|
||||
func (b *Bitmap) Difference(other *Bitmap) *Bitmap {
|
||||
output := NewBitmap()
|
||||
output.Source = b.Source
|
||||
|
||||
iiter, _ := b.Containers.Iterator(0)
|
||||
jiter, _ := other.Containers.Iterator(0)
|
||||
i, j := iiter.Next(), jiter.Next()
|
||||
|
|
@ -2668,6 +2667,7 @@ func (c *Container) arrayRemove(v uint16) (*Container, bool) {
|
|||
}
|
||||
// removing the last item? we can just return the empty container.
|
||||
if c.N() == 1 {
|
||||
c.n = 0
|
||||
return nil, true
|
||||
}
|
||||
c = c.Thaw()
|
||||
|
|
@ -2684,6 +2684,7 @@ func (c *Container) bitmapRemove(v uint16) (*Container, bool) {
|
|||
}
|
||||
// removing the last item? we can just return the empty container.
|
||||
if c.N() == 1 {
|
||||
c.n = 0
|
||||
return nil, true
|
||||
}
|
||||
c = c.Thaw()
|
||||
|
|
@ -2709,6 +2710,7 @@ func (c *Container) runRemove(v uint16) (*Container, bool) {
|
|||
}
|
||||
// removing the last item? we can just return the empty container.
|
||||
if c.N() == 1 {
|
||||
c.n = 0
|
||||
return nil, true
|
||||
}
|
||||
c = c.Thaw()
|
||||
|
|
@ -5451,3 +5453,436 @@ type containerUnionSummaryStats struct {
|
|||
// extremely dense containers.
|
||||
hasMaxRange bool
|
||||
}
|
||||
|
||||
func (b *Bitmap) DifferenceInPlace(others ...*Bitmap) {
|
||||
var (
|
||||
requiredSliceSize = len(others)
|
||||
// To avoid having to allocate a slice everytime, if the number of bitmaps
|
||||
// being unioned is small enough we can just use this stack-allocated array.
|
||||
staticHandledIters = [20]handledIter{}
|
||||
bitmapIters handledIters
|
||||
target = b
|
||||
removeContinerKeys = [pilosa.ShardWidth / (1 << 16)]uint64{} //i need a better guess for this
|
||||
)
|
||||
|
||||
if requiredSliceSize <= 20 {
|
||||
bitmapIters = staticHandledIters[:0]
|
||||
} else {
|
||||
bitmapIters = make(handledIters, 0, requiredSliceSize)
|
||||
}
|
||||
|
||||
for _, other := range others {
|
||||
otherIter, _ := other.Containers.Iterator(0)
|
||||
if otherIter.Next() {
|
||||
bitmapIters = append(bitmapIters, handledIter{
|
||||
iter: otherIter,
|
||||
hasNext: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
targetItr, _ := target.Containers.Iterator(0)
|
||||
// Go through all the containers and remove the other bits
|
||||
n := 0
|
||||
for targetItr.Next() {
|
||||
targetKey, curContainer := targetItr.Value()
|
||||
// Loop until every iters current value has been handled.
|
||||
|
||||
for _, iIter := range bitmapIters {
|
||||
if !iIter.hasNext {
|
||||
continue
|
||||
}
|
||||
iKey, iContainer := iIter.iter.Value()
|
||||
if targetKey == iKey {
|
||||
curContainer.differenceInPlaceO(iContainer)
|
||||
if curContainer.N() == 0 { //according to comments N = 1-count, so N should == 1 if 0 elements
|
||||
removeContinerKeys[n] = iKey
|
||||
n++
|
||||
break
|
||||
}
|
||||
iIter.hasNext = iIter.iter.Next()
|
||||
} else if targetKey > iKey {
|
||||
iIter.hasNext = iIter.iter.Next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
b.Containers.Remove(removeContinerKeys[i])
|
||||
|
||||
}
|
||||
target.Containers.Repair()
|
||||
}
|
||||
|
||||
func (c *Container) differenceInPlace(other *Container) {
|
||||
if other.isArray() {
|
||||
for _, v := range other.array() {
|
||||
c.remove(v)
|
||||
}
|
||||
} else if other.isBitmap() {
|
||||
for i, word := range other.bitmap() {
|
||||
for word != 0 {
|
||||
t := word & -word
|
||||
c.remove(uint16((i*64 + int(popcount(t-1)))))
|
||||
word ^= t
|
||||
}
|
||||
}
|
||||
} else if other.isRun() {
|
||||
for _, r := range other.runs() {
|
||||
for v := int(r.start); v <= int(r.last); v++ {
|
||||
c.remove(uint16(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Container) differenceInPlaceO(other *Container) {
|
||||
if other.isArray() {
|
||||
if c.isArray() {
|
||||
differenceArrayArrayInPlace(c, other)
|
||||
} else if c.isBitmap() {
|
||||
differenceBitmapArrayInPlace(c, other)
|
||||
} else if c.isRun() {
|
||||
differenceRunArrayInPlace(c, other)
|
||||
}
|
||||
} else if other.isBitmap() {
|
||||
if c.isArray() {
|
||||
differenceArrayBitmapInPlace(c, other)
|
||||
} else if c.isBitmap() {
|
||||
differenceBitmapBitmapInPlace(c, other)
|
||||
} else if c.isRun() {
|
||||
differenceRunBitmapInPlace(c, other)
|
||||
}
|
||||
} else if other.isRun() {
|
||||
if c.isArray() {
|
||||
differenceArrayRunInPlace(c, other)
|
||||
} else if c.isBitmap() {
|
||||
differenceBitmapRunInPlace(c, other)
|
||||
} else if c.isRun() {
|
||||
differenceRunRunInPlace(c, other)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func differenceArrayArrayInPlace(output, other *Container) {
|
||||
statsHit("differenceInPlace/ArrayArray")
|
||||
aa, ab := output.array(), other.array()
|
||||
na, nb := len(aa), len(ab)
|
||||
n := 0
|
||||
for i, j := 0, 0; i < na; {
|
||||
va := aa[i]
|
||||
if j >= nb {
|
||||
aa[n] = va
|
||||
n++
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
vb := ab[j]
|
||||
if va < vb {
|
||||
aa[n] = va
|
||||
n++
|
||||
i++
|
||||
} else if va > vb {
|
||||
j++
|
||||
} else {
|
||||
i, j = i+1, j+1
|
||||
}
|
||||
}
|
||||
aa = aa[:n]
|
||||
output.setArray(aa)
|
||||
}
|
||||
func differenceArrayBitmapInPlace(c, other *Container) {
|
||||
statsHit("differenceInPlace/ArrayBitmap")
|
||||
aa := c.array()
|
||||
n := 0
|
||||
bitmap := other.bitmap()
|
||||
for _, va := range aa {
|
||||
bmidx := va / 64
|
||||
bidx := va % 64
|
||||
mask := uint64(1) << bidx
|
||||
b := bitmap[bmidx]
|
||||
|
||||
if mask&^b > 0 {
|
||||
aa[n] = va
|
||||
n++
|
||||
}
|
||||
}
|
||||
aa = aa[:n]
|
||||
c.setArray(aa)
|
||||
}
|
||||
|
||||
func differenceArrayRunInPlace(c, other *Container) {
|
||||
statsHit("differenceInPlace/ArrayRun")
|
||||
|
||||
i := 0 // array index
|
||||
j := 0 // run index
|
||||
aa, rb := c.array(), other.runs()
|
||||
if len(aa) == 0 || len(rb) == 0 {
|
||||
return
|
||||
}
|
||||
n := 0
|
||||
|
||||
// handle overlap
|
||||
for i < len(aa) {
|
||||
|
||||
// keep all array elements before beginning of runs
|
||||
if aa[i] < rb[j].start {
|
||||
aa[n] = aa[i]
|
||||
n++
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// if array element in run, skip it
|
||||
if aa[i] >= rb[j].start && aa[i] <= rb[j].last {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// if array element larger than current run, check next run
|
||||
if aa[i] > rb[j].last {
|
||||
j++
|
||||
if j == len(rb) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for ; i < len(aa); i++ {
|
||||
aa[n] = aa[i]
|
||||
n++
|
||||
}
|
||||
aa = aa[:n]
|
||||
c.setArray(aa)
|
||||
}
|
||||
|
||||
func differenceBitmapArrayInPlace(c, other *Container) {
|
||||
statsHit("differenceInPlace/BitmapArray")
|
||||
bitmap := c.bitmap()
|
||||
|
||||
n := c.N()
|
||||
for _, v := range other.array() {
|
||||
if c.bitmapContains(v) {
|
||||
bitmap[v/64] &^= (uint64(1) << uint(v%64))
|
||||
n--
|
||||
}
|
||||
}
|
||||
c.setN(n)
|
||||
if n < ArrayMaxSize {
|
||||
c.bitmapToArray() // With This Work
|
||||
}
|
||||
}
|
||||
|
||||
func differenceBitmapBitmapInPlace(c, other *Container) {
|
||||
statsHit("differenceInPlace/BitmapBitmap")
|
||||
// local variables added to prevent BCE checks in loop
|
||||
// see https://go101.org/article/bounds-check-elimination.html
|
||||
|
||||
var (
|
||||
ab = c.bitmap()[:bitmapN]
|
||||
bb = other.bitmap()[:bitmapN]
|
||||
n int32
|
||||
)
|
||||
|
||||
for i := 0; i < bitmapN; i++ {
|
||||
ab[i] = ab[i] & (^bb[i])
|
||||
n += int32(popcount(ab[i]))
|
||||
}
|
||||
c.setN(n)
|
||||
if n < ArrayMaxSize {
|
||||
c.bitmapToArray() // Will this work?
|
||||
}
|
||||
}
|
||||
func differenceBitmapRunInPlace(c, other *Container) {
|
||||
statsHit("differenceInPlace/BitmapRun")
|
||||
for _, run := range other.runs() {
|
||||
c.bitmapZeroRange(uint64(run.start), uint64(run.last)+1)
|
||||
}
|
||||
}
|
||||
func differenceRunArrayInPlace(c, other *Container) {
|
||||
statsHit("differenceInPlace/RunArray")
|
||||
ra, ab := c.runs(), other.array()
|
||||
if len(ab) == 0 {
|
||||
return
|
||||
}
|
||||
runs := make([]interval16, 0, len(ra))
|
||||
bidx := 0
|
||||
vb := ab[bidx]
|
||||
|
||||
RUNLOOP:
|
||||
for _, run := range ra {
|
||||
start := run.start
|
||||
for vb < run.start {
|
||||
bidx++
|
||||
if bidx >= len(ab) {
|
||||
break
|
||||
}
|
||||
vb = ab[bidx]
|
||||
}
|
||||
for vb >= run.start && vb <= run.last {
|
||||
if vb == start {
|
||||
if vb == 65535 { // overflow
|
||||
break RUNLOOP
|
||||
}
|
||||
start++
|
||||
bidx++
|
||||
if bidx >= len(ab) {
|
||||
break
|
||||
}
|
||||
vb = ab[bidx]
|
||||
continue
|
||||
}
|
||||
runs = append(runs, interval16{start: start, last: vb - 1})
|
||||
if vb == 65535 { // overflow
|
||||
break RUNLOOP
|
||||
}
|
||||
start = vb + 1
|
||||
bidx++
|
||||
if bidx >= len(ab) {
|
||||
break
|
||||
}
|
||||
vb = ab[bidx]
|
||||
}
|
||||
|
||||
if start <= run.last {
|
||||
runs = append(runs, interval16{start: start, last: run.last})
|
||||
}
|
||||
}
|
||||
c.setRuns(runs)
|
||||
c.n = 0
|
||||
for _, run := range runs {
|
||||
c.n += int32(run.last-run.start) + 1
|
||||
}
|
||||
c.optimize()
|
||||
}
|
||||
func differenceRunBitmapInPlace(c, other *Container) {
|
||||
statsHit("differenceInPlace/RunBitmap")
|
||||
ra := c.runs()
|
||||
// If a is full, difference is the flip of b.
|
||||
if len(ra) > 0 && ra[0].start == 0 && ra[0].last == 65535 {
|
||||
clone := other.Clone()
|
||||
bitmap := clone.bitmap()
|
||||
for i, word := range other.bitmap() {
|
||||
bitmap[i] = ^word
|
||||
}
|
||||
c.setTyp(containerBitmap)
|
||||
c.setMapped(false)
|
||||
c.setBitmap(bitmap)
|
||||
c.setN(c.count())
|
||||
return
|
||||
}
|
||||
runs := make([]interval16, 0, len(ra))
|
||||
for _, inputRun := range ra {
|
||||
run := inputRun
|
||||
add := true
|
||||
for bit := inputRun.start; bit <= inputRun.last; bit++ {
|
||||
if other.bitmapContains(bit) {
|
||||
if run.start == bit {
|
||||
if bit == 65535 { //overflow
|
||||
add = false
|
||||
}
|
||||
|
||||
run.start++
|
||||
} else if bit == run.last {
|
||||
run.last--
|
||||
} else {
|
||||
run.last = bit - 1
|
||||
if run.last >= run.start {
|
||||
runs = append(runs, run)
|
||||
}
|
||||
run.start = bit + 1
|
||||
run.last = inputRun.last
|
||||
}
|
||||
if run.start > run.last {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if bit == 65535 { //overflow
|
||||
break
|
||||
}
|
||||
}
|
||||
if run.start <= run.last {
|
||||
if add {
|
||||
runs = append(runs, run)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.setRuns(runs)
|
||||
c.n = 0
|
||||
for _, run := range runs {
|
||||
c.n += int32(run.last-run.start) + 1
|
||||
}
|
||||
if c.N() < ArrayMaxSize && int32(len(runs)) > c.N()/2 {
|
||||
c.runToArray()
|
||||
} else if len(runs) > runMaxSize {
|
||||
c.runToBitmap()
|
||||
}
|
||||
}
|
||||
func differenceRunRunInPlace(c, other *Container) {
|
||||
statsHit("differenceInPlace/RunRun")
|
||||
|
||||
ra, rb := c.runs(), other.runs()
|
||||
if len(ra) == 0 || len(rb) == 0 {
|
||||
return
|
||||
}
|
||||
apos := 0 // current a-run index
|
||||
bpos := 0 // current b-run index
|
||||
astart := ra[apos].start
|
||||
alast := ra[apos].last
|
||||
bstart := rb[bpos].start
|
||||
blast := rb[bpos].last
|
||||
alen := len(ra)
|
||||
blen := len(rb)
|
||||
|
||||
runs := make([]interval16, 0, alen+blen) // TODO allocate max then truncate? or something else
|
||||
// cardinality upper bound: sum of number of runs
|
||||
// each B-run could split an A-run in two, up to len(b.runs) times
|
||||
|
||||
for apos < alen && bpos < blen {
|
||||
switch {
|
||||
case alast < bstart:
|
||||
// current A-run entirely precedes current B-run: keep full A-run, advance to next A-run
|
||||
runs = append(runs, interval16{start: astart, last: alast})
|
||||
apos++
|
||||
if apos < alen {
|
||||
astart = ra[apos].start
|
||||
alast = ra[apos].last
|
||||
}
|
||||
case blast < astart:
|
||||
// current B-run entirely precedes current A-run: advance to next B-run
|
||||
bpos++
|
||||
if bpos < blen {
|
||||
bstart = rb[bpos].start
|
||||
blast = rb[bpos].last
|
||||
}
|
||||
default:
|
||||
// overlap
|
||||
if astart < bstart {
|
||||
runs = append(runs, interval16{start: astart, last: bstart - 1})
|
||||
}
|
||||
if alast > blast {
|
||||
astart = blast + 1
|
||||
} else {
|
||||
apos++
|
||||
if apos < alen {
|
||||
astart = ra[apos].start
|
||||
alast = ra[apos].last
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if apos < alen {
|
||||
runs = append(runs, interval16{start: astart, last: alast})
|
||||
apos++
|
||||
if apos < alen {
|
||||
runs = append(runs, ra[apos:]...)
|
||||
}
|
||||
}
|
||||
c.setRuns(runs)
|
||||
c.n = 0
|
||||
for _, run := range runs {
|
||||
c.n += int32(run.last-run.start) + 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2709,6 +2709,14 @@ func unionInPlaceWrapper(a, b *Container) *Container {
|
|||
out.UnionInPlace(B)
|
||||
return out.Containers.Get(0)
|
||||
}
|
||||
func differenceInPlaceWrapper(a, b *Container) *Container {
|
||||
out := NewBitmap()
|
||||
out.Containers.Put(0, a.Clone())
|
||||
B := NewBitmap()
|
||||
B.Containers.Put(0, b)
|
||||
out.DifferenceInPlace(B)
|
||||
return out.Containers.Get(0)
|
||||
}
|
||||
|
||||
func TestContainerCombinations(t *testing.T) {
|
||||
|
||||
|
|
@ -3283,6 +3291,120 @@ func TestContainerCombinations(t *testing.T) {
|
|||
{flip, "outerBitsSet", "", "innerBitsSet"},
|
||||
{flip, "oddBitsSet", "", "evenBitsSet"},
|
||||
{flip, "evenBitsSet", "", "oddBitsSet"},
|
||||
|
||||
// differenceInPlace
|
||||
{differenceInPlaceWrapper, "empty", "empty", "empty"},
|
||||
{differenceInPlaceWrapper, "empty", "full", "empty"},
|
||||
{differenceInPlaceWrapper, "empty", "firstBitSet", "empty"},
|
||||
{differenceInPlaceWrapper, "empty", "lastBitSet", "empty"},
|
||||
{differenceInPlaceWrapper, "empty", "firstBitUnset", "empty"},
|
||||
{differenceInPlaceWrapper, "empty", "lastBitUnset", "empty"},
|
||||
{differenceInPlaceWrapper, "empty", "innerBitsSet", "empty"},
|
||||
{differenceInPlaceWrapper, "empty", "outerBitsSet", "empty"},
|
||||
{differenceInPlaceWrapper, "empty", "oddBitsSet", "empty"},
|
||||
{differenceInPlaceWrapper, "empty", "evenBitsSet", "empty"},
|
||||
//
|
||||
{differenceInPlaceWrapper, "full", "empty", "full"},
|
||||
{differenceInPlaceWrapper, "full", "full", "empty"},
|
||||
{differenceInPlaceWrapper, "full", "firstBitSet", "firstBitUnset"},
|
||||
{differenceInPlaceWrapper, "full", "lastBitSet", "lastBitUnset"},
|
||||
{differenceInPlaceWrapper, "full", "firstBitUnset", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "full", "lastBitUnset", "lastBitSet"},
|
||||
{differenceInPlaceWrapper, "full", "innerBitsSet", "outerBitsSet"},
|
||||
{differenceInPlaceWrapper, "full", "outerBitsSet", "innerBitsSet"},
|
||||
{differenceInPlaceWrapper, "full", "oddBitsSet", "evenBitsSet"},
|
||||
{differenceInPlaceWrapper, "full", "evenBitsSet", "oddBitsSet"},
|
||||
//
|
||||
{differenceInPlaceWrapper, "firstBitSet", "empty", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "firstBitSet", "full", "empty"},
|
||||
{differenceInPlaceWrapper, "firstBitSet", "firstBitSet", "empty"},
|
||||
{differenceInPlaceWrapper, "firstBitSet", "lastBitSet", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "firstBitSet", "firstBitUnset", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "firstBitSet", "lastBitUnset", "empty"},
|
||||
{differenceInPlaceWrapper, "firstBitSet", "innerBitsSet", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "firstBitSet", "outerBitsSet", "empty"},
|
||||
{differenceInPlaceWrapper, "firstBitSet", "oddBitsSet", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "firstBitSet", "evenBitsSet", "empty"},
|
||||
//
|
||||
{differenceInPlaceWrapper, "lastBitSet", "empty", "lastBitSet"},
|
||||
{differenceInPlaceWrapper, "lastBitSet", "full", "empty"},
|
||||
{differenceInPlaceWrapper, "lastBitSet", "firstBitSet", "lastBitSet"},
|
||||
{differenceInPlaceWrapper, "lastBitSet", "lastBitSet", "empty"},
|
||||
{differenceInPlaceWrapper, "lastBitSet", "firstBitUnset", "empty"},
|
||||
{differenceInPlaceWrapper, "lastBitSet", "lastBitUnset", "lastBitSet"},
|
||||
{differenceInPlaceWrapper, "lastBitSet", "innerBitsSet", "lastBitSet"},
|
||||
{differenceInPlaceWrapper, "lastBitSet", "outerBitsSet", "empty"},
|
||||
{differenceInPlaceWrapper, "lastBitSet", "oddBitsSet", "empty"},
|
||||
{differenceInPlaceWrapper, "lastBitSet", "evenBitsSet", "lastBitSet"},
|
||||
//
|
||||
{differenceInPlaceWrapper, "firstBitUnset", "empty", "firstBitUnset"},
|
||||
{differenceInPlaceWrapper, "firstBitUnset", "full", "empty"},
|
||||
{differenceInPlaceWrapper, "firstBitUnset", "firstBitSet", "firstBitUnset"},
|
||||
{differenceInPlaceWrapper, "firstBitUnset", "lastBitSet", "innerBitsSet"},
|
||||
{differenceInPlaceWrapper, "firstBitUnset", "firstBitUnset", "empty"},
|
||||
{differenceInPlaceWrapper, "firstBitUnset", "lastBitUnset", "lastBitSet"},
|
||||
{differenceInPlaceWrapper, "firstBitUnset", "innerBitsSet", "lastBitSet"},
|
||||
{differenceInPlaceWrapper, "firstBitUnset", "outerBitsSet", "innerBitsSet"},
|
||||
//{differenceInPlaceWrapper, "firstBitUnset", "oddBitsSet", ""},
|
||||
{differenceInPlaceWrapper, "firstBitUnset", "evenBitsSet", "oddBitsSet"},
|
||||
//
|
||||
{differenceInPlaceWrapper, "lastBitUnset", "empty", "lastBitUnset"},
|
||||
{differenceInPlaceWrapper, "lastBitUnset", "full", "empty"},
|
||||
{differenceInPlaceWrapper, "lastBitUnset", "firstBitSet", "innerBitsSet"},
|
||||
{differenceInPlaceWrapper, "lastBitUnset", "lastBitSet", "lastBitUnset"},
|
||||
{differenceInPlaceWrapper, "lastBitUnset", "firstBitUnset", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "lastBitUnset", "lastBitUnset", "empty"},
|
||||
{differenceInPlaceWrapper, "lastBitUnset", "innerBitsSet", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "lastBitUnset", "outerBitsSet", "innerBitsSet"},
|
||||
{differenceInPlaceWrapper, "lastBitUnset", "oddBitsSet", "evenBitsSet"},
|
||||
//{differenceInPlaceWrapper, "lastBitUnset", "evenBitsSet", ""},
|
||||
//
|
||||
{differenceInPlaceWrapper, "innerBitsSet", "empty", "innerBitsSet"},
|
||||
{differenceInPlaceWrapper, "innerBitsSet", "full", "empty"},
|
||||
{differenceInPlaceWrapper, "innerBitsSet", "firstBitSet", "innerBitsSet"},
|
||||
{differenceInPlaceWrapper, "innerBitsSet", "lastBitSet", "innerBitsSet"},
|
||||
{differenceInPlaceWrapper, "innerBitsSet", "firstBitUnset", "empty"},
|
||||
{differenceInPlaceWrapper, "innerBitsSet", "lastBitUnset", "empty"},
|
||||
{differenceInPlaceWrapper, "innerBitsSet", "innerBitsSet", "empty"},
|
||||
{differenceInPlaceWrapper, "innerBitsSet", "outerBitsSet", "innerBitsSet"},
|
||||
//{differenceInPlaceWrapper, "innerBitsSet", "oddBitsSet", ""},
|
||||
//{differenceInPlaceWrapper, "innerBitsSet", "evenBitsSet", ""},
|
||||
//
|
||||
{differenceInPlaceWrapper, "outerBitsSet", "empty", "outerBitsSet"},
|
||||
{differenceInPlaceWrapper, "outerBitsSet", "full", "empty"},
|
||||
{differenceInPlaceWrapper, "outerBitsSet", "firstBitSet", "lastBitSet"},
|
||||
{differenceInPlaceWrapper, "outerBitsSet", "lastBitSet", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "outerBitsSet", "firstBitUnset", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "outerBitsSet", "lastBitUnset", "lastBitSet"},
|
||||
{differenceInPlaceWrapper, "outerBitsSet", "innerBitsSet", "outerBitsSet"},
|
||||
{differenceInPlaceWrapper, "outerBitsSet", "outerBitsSet", "empty"},
|
||||
{differenceInPlaceWrapper, "outerBitsSet", "oddBitsSet", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "outerBitsSet", "evenBitsSet", "lastBitSet"},
|
||||
//
|
||||
{differenceInPlaceWrapper, "oddBitsSet", "empty", "oddBitsSet"},
|
||||
{differenceInPlaceWrapper, "oddBitsSet", "full", "empty"},
|
||||
{differenceInPlaceWrapper, "oddBitsSet", "firstBitSet", "oddBitsSet"},
|
||||
//{differenceInPlaceWrapper, "oddBitsSet", "lastBitSet", ""},
|
||||
{differenceInPlaceWrapper, "oddBitsSet", "firstBitUnset", "empty"},
|
||||
{differenceInPlaceWrapper, "oddBitsSet", "lastBitUnset", "lastBitSet"},
|
||||
{differenceInPlaceWrapper, "oddBitsSet", "innerBitsSet", "lastBitSet"},
|
||||
//{difference, "oddBitsSet", "outerBitsSet", ""},
|
||||
{differenceInPlaceWrapper, "oddBitsSet", "oddBitsSet", "empty"},
|
||||
{differenceInPlaceWrapper, "oddBitsSet", "evenBitsSet", "oddBitsSet"},
|
||||
//
|
||||
{differenceInPlaceWrapper, "evenBitsSet", "empty", "evenBitsSet"},
|
||||
{differenceInPlaceWrapper, "evenBitsSet", "full", "empty"},
|
||||
//{difference, "evenBitsSet", "firstBitSet", ""},
|
||||
{differenceInPlaceWrapper, "evenBitsSet", "lastBitSet", "evenBitsSet"},
|
||||
{differenceInPlaceWrapper, "evenBitsSet", "firstBitUnset", "firstBitSet"},
|
||||
{differenceInPlaceWrapper, "evenBitsSet", "lastBitUnset", "empty"},
|
||||
{differenceInPlaceWrapper, "evenBitsSet", "innerBitsSet", "firstBitSet"},
|
||||
//{difference, "evenBitsSet", "outerBitsSet", ""},
|
||||
{differenceInPlaceWrapper, "evenBitsSet", "oddBitsSet", "evenBitsSet"},
|
||||
{differenceInPlaceWrapper, "evenBitsSet", "evenBitsSet", "empty"},
|
||||
/*
|
||||
*/
|
||||
|
||||
}
|
||||
for _, testOp := range testOps {
|
||||
for _, x := range containerTypes {
|
||||
|
|
@ -3896,3 +4018,14 @@ func TestBitmapAny(t *testing.T) {
|
|||
t.Error("shouldn't be any left")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStuff(t *testing.T) {
|
||||
a := doContainer(containerRun, runFull())
|
||||
b := doContainer(containerBitmap, bitmapFull())
|
||||
// b := doContainer(containerBitmap, bitmapLastBitSet())
|
||||
r := differenceInPlaceWrapper(a, b)
|
||||
if r.N() != 0 {
|
||||
t.Error("fail")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1739,3 +1739,51 @@ func BenchmarkUnionBulk(b *testing.B) {
|
|||
UnionInPlace(data.a1, data.a2, data.b, data.r1, data.r2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBitmap_differenceInPlace(t *testing.T) {
|
||||
bm := testBM()
|
||||
//the array
|
||||
arraybm := roaring.NewSliceBitmap()
|
||||
bitmapbm := roaring.NewSliceBitmap()
|
||||
smallrunbm := roaring.NewSliceBitmap()
|
||||
largerunbm := roaring.NewSliceBitmap()
|
||||
|
||||
for i := uint64(0); i < 1024; i += 4 {
|
||||
_, _ = arraybm.Add((1 << 16) + i)
|
||||
}
|
||||
arraybm.Optimize()
|
||||
|
||||
for i := uint64(0); i < 16384; i += 2 {
|
||||
_, _ = bitmapbm.Add((2 << 16) + i)
|
||||
}
|
||||
bitmapbm.Optimize()
|
||||
//small run
|
||||
for i := uint64(0); i < 1024; i++ {
|
||||
_, _ = smallrunbm.Add((3 << 16) + i)
|
||||
}
|
||||
smallrunbm.Optimize()
|
||||
for i := uint64(0); i < 65535; i++ {
|
||||
_, _ = largerunbm.Add((4 << 16) + i)
|
||||
}
|
||||
smallrunbm.Optimize()
|
||||
bm.DifferenceInPlace(arraybm, bitmapbm, smallrunbm, largerunbm)
|
||||
if bm.Count() != 0 {
|
||||
t.Fatalf("expected bitmap to be empty, it wasn't. %d", bm.Count())
|
||||
}
|
||||
bm = testBM()
|
||||
bm.DifferenceInPlace(bitmapbm, smallrunbm, largerunbm)
|
||||
if bm.Count() != 256 {
|
||||
t.Fatalf("expected bitmap to have 256, it wasn't. %d", bm.Count())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDifferencInPlace(b *testing.B) {
|
||||
data := getBenchData(b)
|
||||
for n := 0; n < b.N; n++ {
|
||||
bm := roaring.NewBitmap()
|
||||
bm.
|
||||
UnionInPlace(data.a1, data.a2, data.b, data.r1, data.r2)
|
||||
bm.
|
||||
DifferenceInPlace(data.a1, data.r2, data.b, data.r1)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue