Skip to content

Commit 3d677d3

Browse files
authored
Merge pull request #200 from RoaringBitmap/bp/iandnot
AndNot: avoid returning bitmapcontainer with arraycontainer cardinality
2 parents 4c23670 + 3c1af42 commit 3d677d3

File tree

5 files changed

+39
-3
lines changed

5 files changed

+39
-3
lines changed

bitmapcontainer.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,12 +857,15 @@ func (bc *bitmapContainer) andNotBitmap(value2 *bitmapContainer) container {
857857
return ac
858858
}
859859

860-
func (bc *bitmapContainer) iandNotBitmapSurely(value2 *bitmapContainer) *bitmapContainer {
860+
func (bc *bitmapContainer) iandNotBitmapSurely(value2 *bitmapContainer) container {
861861
newCardinality := int(popcntMaskSlice(bc.bitmap, value2.bitmap))
862862
for k := 0; k < len(bc.bitmap); k++ {
863863
bc.bitmap[k] = bc.bitmap[k] &^ value2.bitmap[k]
864864
}
865865
bc.cardinality = newCardinality
866+
if bc.getCardinality() <= arrayDefaultMaxSize {
867+
return bc.toArrayContainer()
868+
}
866869
return bc
867870
}
868871

roaring_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package roaring
22

33
import (
4+
"bytes"
45
"log"
56
"math"
67
"math/rand"
@@ -163,6 +164,30 @@ func TestRoaringBitmapAddOffset(t *testing.T) {
163164
}
164165
}
165166

167+
func TestRoaringInPlaceAndNotBitmapContainer(t *testing.T) {
168+
bm := NewBitmap()
169+
for i := 0; i < 8192; i++ {
170+
bm.Add(uint32(i))
171+
}
172+
toRemove := NewBitmap()
173+
for i := 128; i < 8192; i++ {
174+
toRemove.Add(uint32(i))
175+
}
176+
bm.AndNot(toRemove)
177+
178+
var b bytes.Buffer
179+
_, err := bm.WriteTo(&b)
180+
if err != nil {
181+
t.Fatal(err)
182+
}
183+
184+
bm2 := NewBitmap()
185+
bm2.ReadFrom(bytes.NewBuffer(b.Bytes()))
186+
if !bm2.Equals(bm) {
187+
t.Errorf("expected %s to equal %s", bm2, bm)
188+
}
189+
}
190+
166191
// https://github.com/RoaringBitmap/roaring/issues/64
167192
func TestFlip64(t *testing.T) {
168193
bm := New()

serialization_generic.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package roaring
44

55
import (
66
"encoding/binary"
7+
"errors"
78
"io"
89
)
910

@@ -26,6 +27,10 @@ func (b *arrayContainer) readFrom(stream io.Reader) (int, error) {
2627
}
2728

2829
func (b *bitmapContainer) writeTo(stream io.Writer) (int, error) {
30+
if b.cardinality <= arrayDefaultMaxSize {
31+
return 0, errors.New("refusing to write bitmap container with cardinality of array container")
32+
}
33+
2934
// Write set
3035
buf := make([]byte, 8*len(b.bitmap))
3136
for i, v := range b.bitmap {

serialization_littleendian.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package roaring
44

55
import (
6+
"errors"
67
"io"
78
"reflect"
89
"unsafe"
@@ -14,6 +15,9 @@ func (ac *arrayContainer) writeTo(stream io.Writer) (int, error) {
1415
}
1516

1617
func (bc *bitmapContainer) writeTo(stream io.Writer) (int, error) {
18+
if bc.cardinality <= arrayDefaultMaxSize {
19+
return 0, errors.New("refusing to write bitmap container with cardinality of array container")
20+
}
1721
buf := uint64SliceAsByteSlice(bc.bitmap)
1822
return stream.Write(buf)
1923
}

serialization_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,12 +493,11 @@ func TestSerializationRunOnly033(t *testing.T) {
493493
func TestSerializationBitmapOnly034(t *testing.T) {
494494

495495
Convey("bitmapContainer writeTo and readFrom should return logically equivalent containers", t, func() {
496-
497496
seed := int64(42)
498497
rand.Seed(seed)
499498

500499
trials := []trial{
501-
{n: 1010, percentFill: .50, ntrial: 10},
500+
{n: 8192, percentFill: .99, ntrial: 10},
502501
}
503502

504503
tester := func(tr trial) {

0 commit comments

Comments
 (0)