Skip to content

Commit

Permalink
Fixed COW implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
lemire committed May 6, 2016
1 parent 91117e6 commit 3751c26
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 77 deletions.
5 changes: 3 additions & 2 deletions fastaggregation.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ main:
s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
} else {

answer.highlowcontainer.appendContainer(s1, x1.highlowcontainer.getContainerAtIndex(pos1).lazyOR(x2.highlowcontainer.getContainerAtIndex(pos2)))
answer.highlowcontainer.appendContainer(s1, x1.highlowcontainer.getContainerAtIndex(pos1).lazyOR(x2.highlowcontainer.getContainerAtIndex(pos2)), false)
pos1++
pos2++
if (pos1 == length1) || (pos2 == length2) {
Expand Down Expand Up @@ -81,7 +81,7 @@ main:
s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
} else {

answer.highlowcontainer.appendContainer(s1, x1.highlowcontainer.getContainerAtIndex(pos1).lazyIOR(x2.highlowcontainer.getContainerAtIndex(pos2)))
answer.highlowcontainer.appendContainer(s1, x1.highlowcontainer.getWritableContainerAtIndex(pos1).lazyIOR(x2.highlowcontainer.getContainerAtIndex(pos2)), false)
pos1++
pos2++
if (pos1 == length1) || (pos2 == length2) {
Expand All @@ -107,6 +107,7 @@ func (x1 *Bitmap) repairAfterLazy() {
switch c.(type) {
case *bitmapContainer:
if c.(*bitmapContainer).cardinality == invalidCardinality {
c = x1.highlowcontainer.getWritableContainerAtIndex(pos)
c.(*bitmapContainer).computeCardinality()
if c.(*bitmapContainer).getCardinality() <= arrayDefaultMaxSize {
x1.highlowcontainer.setContainerAtIndex(pos, c.(*bitmapContainer).toArrayContainer())
Expand Down
56 changes: 35 additions & 21 deletions roaring.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,23 @@ func (rb *Bitmap) Add(x uint32) {
i := ra.getIndex(hb)
if i >= 0 {
var c container
if ra.hasDirty() {
c = ra.getWritableContainerAtIndex(i)
} else {
c = ra.getContainerAtIndex(i)
}
c = ra.getWritableContainerAtIndex(i)
c = c.add(lowbits(x))
rb.highlowcontainer.setContainerAtIndex(i, c)
} else {
newac := newArrayContainer()
rb.highlowcontainer.insertNewKeyValueAt(-i-1, hb, newac.add(lowbits(x)))
}
}

// Add the integer x to the bitmap
func (rb *Bitmap) VerboseAdd(x uint32) {
hb := highbits(x)
ra := &rb.highlowcontainer
i := ra.getIndex(hb)
if i >= 0 {
var c container
c = ra.getWritableContainerAtIndex(i)
c = c.add(lowbits(x))
rb.highlowcontainer.setContainerAtIndex(i, c)
} else {
Expand All @@ -238,7 +250,7 @@ func (rb *Bitmap) CheckedAdd(x uint32) bool {
hb := highbits(x)
i := rb.highlowcontainer.getIndex(hb)
if i >= 0 {
C := rb.highlowcontainer.getContainerAtIndex(i)
C := rb.highlowcontainer.getWritableContainerAtIndex(i)
oldcard := C.getCardinality()
C = C.add(lowbits(x))
rb.highlowcontainer.setContainerAtIndex(i, C)
Expand Down Expand Up @@ -274,7 +286,7 @@ func (rb *Bitmap) CheckedRemove(x uint32) bool {
hb := highbits(x)
i := rb.highlowcontainer.getIndex(hb)
if i >= 0 {
C := rb.highlowcontainer.getContainerAtIndex(i)
C := rb.highlowcontainer.getWritableContainerAtIndex(i)
oldcard := C.getCardinality()
C = C.remove(lowbits(x))
rb.highlowcontainer.setContainerAtIndex(i, C)
Expand Down Expand Up @@ -357,7 +369,7 @@ main:
c2 := x2.highlowcontainer.getContainerAtIndex(pos2)
diff := c1.iand(c2)
if diff.getCardinality() > 0 {
rb.highlowcontainer.replaceKeyAndContainerAtIndex(intersectionsize, s1, diff)
rb.highlowcontainer.replaceKeyAndContainerAtIndex(intersectionsize, s1, diff, false)
intersectionsize++
}
pos1++
Expand Down Expand Up @@ -456,7 +468,7 @@ main:
s2 := x2.highlowcontainer.getKeyAtIndex(pos2)
for {
if s1 == s2 {
c1 := rb.highlowcontainer.getWritableContainerAtIndex(pos1)
c1 := rb.highlowcontainer.getContainerAtIndex(pos1)
c2 := x2.highlowcontainer.getContainerAtIndex(pos2)
diff := c1.and(c2)
answer += uint64(diff.getCardinality()) // TODO: could be faster if we did not have to compute diff
Expand Down Expand Up @@ -602,7 +614,7 @@ main:
c2 := x2.highlowcontainer.getContainerAtIndex(pos2)
diff := c1.iandNot(c2)
if diff.getCardinality() > 0 {
rb.highlowcontainer.replaceKeyAndContainerAtIndex(intersectionsize, s1, diff)
rb.highlowcontainer.replaceKeyAndContainerAtIndex(intersectionsize, s1, diff, false)
intersectionsize++
}
pos1++
Expand All @@ -613,8 +625,9 @@ main:
s1 = rb.highlowcontainer.getKeyAtIndex(pos1)
s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
} else if s1 < s2 {
c1 := rb.highlowcontainer.getWritableContainerAtIndex(pos1)
rb.highlowcontainer.replaceKeyAndContainerAtIndex(intersectionsize, s1, c1)
c1 := rb.highlowcontainer.getContainerAtIndex(pos1)
mustCopyOnWrite := rb.highlowcontainer.needsCopyOnWrite(pos1)
rb.highlowcontainer.replaceKeyAndContainerAtIndex(intersectionsize, s1, c1, mustCopyOnWrite)
intersectionsize++
pos1++
if pos1 == length1 {
Expand All @@ -637,7 +650,8 @@ main:
for pos1 < length1 {
c1 := rb.highlowcontainer.getContainerAtIndex(pos1)
s1 := rb.highlowcontainer.getKeyAtIndex(pos1)
rb.highlowcontainer.replaceKeyAndContainerAtIndex(intersectionsize, s1, c1)
mustCopyOnWrite := rb.highlowcontainer.needsCopyOnWrite(pos1)
rb.highlowcontainer.replaceKeyAndContainerAtIndex(intersectionsize, s1, c1, mustCopyOnWrite)
intersectionsize++
pos1++
}
Expand Down Expand Up @@ -673,7 +687,7 @@ main:
s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
} else {

answer.highlowcontainer.appendContainer(s1, x1.highlowcontainer.getContainerAtIndex(pos1).or(x2.highlowcontainer.getContainerAtIndex(pos2)))
answer.highlowcontainer.appendContainer(s1, x1.highlowcontainer.getContainerAtIndex(pos1).or(x2.highlowcontainer.getContainerAtIndex(pos2)), false)
pos1++
pos2++
if (pos1 == length1) || (pos2 == length2) {
Expand Down Expand Up @@ -709,7 +723,7 @@ main:
C = C.and(x2.highlowcontainer.getContainerAtIndex(pos2))

if C.getCardinality() > 0 {
answer.highlowcontainer.appendContainer(s1, C)
answer.highlowcontainer.appendContainer(s1, C, false)
}
pos1++
pos2++
Expand Down Expand Up @@ -756,7 +770,7 @@ func Xor(x1, x2 *Bitmap) *Bitmap {
} else {
c := x1.highlowcontainer.getContainerAtIndex(pos1).xor(x2.highlowcontainer.getContainerAtIndex(pos2))
if c.getCardinality() > 0 {
answer.highlowcontainer.appendContainer(s1, c)
answer.highlowcontainer.appendContainer(s1, c, false)
}
pos1++
pos2++
Expand Down Expand Up @@ -799,7 +813,7 @@ main:
c2 := x2.highlowcontainer.getContainerAtIndex(pos2)
diff := c1.andNot(c2)
if diff.getCardinality() > 0 {
answer.highlowcontainer.appendContainer(s1, diff)
answer.highlowcontainer.appendContainer(s1, diff, false)
}
pos1++
pos2++
Expand Down Expand Up @@ -909,7 +923,7 @@ func (rb *Bitmap) AddRange(rangeStart, rangeEnd uint64) {
i := rb.highlowcontainer.getIndex(hb)

if i >= 0 {
c := rb.highlowcontainer.getContainerAtIndex(i).iaddRange(int(containerStart), int(containerLast+1))
c := rb.highlowcontainer.getWritableContainerAtIndex(i).iaddRange(int(containerStart), int(containerLast+1))
rb.highlowcontainer.setContainerAtIndex(i, c)
} else { // *think* the range of ones must never be
// empty.
Expand Down Expand Up @@ -938,7 +952,7 @@ func (rb *Bitmap) RemoveRange(rangeStart, rangeEnd uint64) {
if i < 0 {
return
}
c := rb.highlowcontainer.getContainerAtIndex(i).iremoveRange(int(lbStart), int(lbLast+1))
c := rb.highlowcontainer.getWritableContainerAtIndex(i).iremoveRange(int(lbStart), int(lbLast+1))
if c.getCardinality() > 0 {
rb.highlowcontainer.setContainerAtIndex(i, c)
} else {
Expand All @@ -951,7 +965,7 @@ func (rb *Bitmap) RemoveRange(rangeStart, rangeEnd uint64) {

if ifirst >= 0 {
if lbStart != 0 {
c := rb.highlowcontainer.getContainerAtIndex(ifirst).iremoveRange(int(lbStart), int(max+1))
c := rb.highlowcontainer.getWritableContainerAtIndex(ifirst).iremoveRange(int(lbStart), int(max+1))
if c.getCardinality() > 0 {
rb.highlowcontainer.setContainerAtIndex(ifirst, c)
ifirst++
Expand All @@ -962,7 +976,7 @@ func (rb *Bitmap) RemoveRange(rangeStart, rangeEnd uint64) {
}
if ilast >= 0 {
if lbLast != max {
c := rb.highlowcontainer.getContainerAtIndex(ilast).iremoveRange(int(0), int(lbLast+1))
c := rb.highlowcontainer.getWritableContainerAtIndex(ilast).iremoveRange(int(0), int(lbLast+1))
if c.getCardinality() > 0 {
rb.highlowcontainer.setContainerAtIndex(ilast, c)
} else {
Expand Down
20 changes: 14 additions & 6 deletions roaring_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package roaring

import (
. "github.com/smartystreets/goconvey/convey"
"github.com/willf/bitset"
"log"
"math/rand"
"strconv"
"testing"

. "github.com/smartystreets/goconvey/convey"
"github.com/willf/bitset"
)

func TestFastCard(t *testing.T) {
Expand Down Expand Up @@ -1239,26 +1238,34 @@ func TestBitmap(t *testing.T) {

So(valide, ShouldEqual, true)
})

}
func TestXORtest4(t *testing.T) {
Convey("XORtest 4", t, func() {
rb := NewBitmap()
rb2 := NewBitmap()
counter := 0

for i := 0; i < 200000; i += 4 {
rb2.AddInt(i)
counter++
}
So(rb2.GetCardinality(), ShouldEqual, counter)
for i := 200000; i < 400000; i += 14 {
rb2.AddInt(i)
counter++
}
So(rb2.GetCardinality(), ShouldEqual, counter)
rb2card := rb2.GetCardinality()
So(rb2card, ShouldEqual, counter)

// check or against an empty bitmap
xorresult := Xor(rb, rb2)
So(xorresult.GetCardinality(), ShouldEqual, counter)
off := Or(rb2, rb)
So(off.GetCardinality(), ShouldEqual, counter)
So(xorresult.Equals(off), ShouldEqual, true)

So(rb2card, ShouldEqual, xorresult.GetCardinality())

for i := 500000; i < 600000; i += 14 {
rb.AddInt(i)
}
Expand All @@ -1268,6 +1275,7 @@ func TestBitmap(t *testing.T) {
// check or against an empty bitmap
xorresult2 := Xor(rb, rb2)
So(rb2card, ShouldEqual, xorresult.GetCardinality())

So(rb2.GetCardinality()+rb.GetCardinality(), ShouldEqual, xorresult2.GetCardinality())

rb.Xor(rb2)
Expand Down Expand Up @@ -1411,7 +1419,7 @@ func TestRoaringArray(t *testing.T) {
})

Convey("Test Insert", t, func() {
a.appendContainer(0, newArrayContainer())
a.appendContainer(0, newArrayContainer(), false)

So(a.size(), ShouldEqual, 1)
})
Expand Down
Loading

0 comments on commit 3751c26

Please sign in to comment.