Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func Backward(b *Bitmap) func(func(uint32) bool) {
// The iterator becomes invalid if the bitmap is modified (e.g., with Add or Remove).
func Unset(b *Bitmap, min, max uint32) func(func(uint32) bool) {
return func(yield func(uint32) bool) {
it := b.UnsetIterator(min, max)
it := b.UnsetIterator(uint64(min), uint64(max)+1)
for it.HasNext() {
if !yield(it.Next()) {
return
Expand Down
16 changes: 8 additions & 8 deletions iter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ func TestUnsetIteratorPeekable(t *testing.T) {
b.AddInt(5)
b.AddInt(8)

it := b.UnsetIterator(3, 10)
it := b.UnsetIterator(3, 11)

// First value should be 3
assert.True(t, it.HasNext())
Expand Down Expand Up @@ -357,7 +357,7 @@ func TestUnsetIteratorPeekable(t *testing.T) {
b.AddInt(8)
b.AddInt(12)

it := b.UnsetIterator(1, 15)
it := b.UnsetIterator(1, 16)

// Skip to values >= 7
it.AdvanceIfNeeded(7)
Expand Down Expand Up @@ -394,7 +394,7 @@ func TestUnsetIteratorPeekable(t *testing.T) {
b := New()
b.AddInt(5)

it := b.UnsetIterator(10, 15)
it := b.UnsetIterator(10, 16)

// Try to advance to a value before our range start
it.AdvanceIfNeeded(5)
Expand All @@ -408,7 +408,7 @@ func TestUnsetIteratorPeekable(t *testing.T) {
b := New()
b.AddInt(5)

it := b.UnsetIterator(10, 15)
it := b.UnsetIterator(10, 16)

// Advance beyond our range
it.AdvanceIfNeeded(20)
Expand All @@ -420,7 +420,7 @@ func TestUnsetIteratorPeekable(t *testing.T) {
t.Run("advance if needed on current value", func(t *testing.T) {
b := New()
b.AddRange(0, 0x10000)
iter := b.UnsetIterator(0, 0x10002)
iter := b.UnsetIterator(0, 0x10003)
var got []uint32
prev := uint32(0)
for len(got) < 10 {
Expand All @@ -439,7 +439,7 @@ func TestUnsetIteratorPeekable(t *testing.T) {
b := New()
b.AddInt(5) // Set bit in middle of range

it := b.UnsetIterator(5, 5) // Range contains only the set bit
it := b.UnsetIterator(5, 6) // Range contains only the set bit

// Should have no values
assert.False(t, it.HasNext())
Expand All @@ -454,7 +454,7 @@ func TestUnsetIteratorPeekable(t *testing.T) {
b := New()
b.Add(4294967294) // Set the value before max

it := b.UnsetIterator(4294967294, 4294967295)
it := b.UnsetIterator(4294967294, 4294967296)

// Should have 4294967295 (max uint32) as it's unset
assert.True(t, it.HasNext())
Expand All @@ -469,7 +469,7 @@ func TestUnsetIteratorPeekable(t *testing.T) {
b := New()
b.Add(4294967295) // Set max uint32

it := b.UnsetIterator(4294967294, 4294967295)
it := b.UnsetIterator(4294967294, 4294967296)

// Should have 4294967294 as it's unset, but not 4294967295
assert.True(t, it.HasNext())
Expand Down
43 changes: 24 additions & 19 deletions roaring.go
Original file line number Diff line number Diff line change
Expand Up @@ -743,20 +743,25 @@ func (ii *manyIntIterator) Initialize(a *Bitmap) {
}

type unsetIterator struct {
min, max uint32
current uint64 // use uint64 to avoid overflow
it IntPeekable
hasNext bool
start, end uint64
current uint64
it IntPeekable
hasNext bool
}

// Initialize configures the unset iterator to iterate over values in [min, max] that are not in the bitmap
func (ui *unsetIterator) Initialize(b *Bitmap, min, max uint32) {
ui.min = min
ui.max = max
ui.current = uint64(min)
// Initialize configures the unset iterator to iterate over values in [start, end) that are not in the bitmap
func (ui *unsetIterator) Initialize(b *Bitmap, start, end uint64) {
if end > 0x100000000 {
panic("end > 0x100000000")
}
ui.start = start
ui.end = end
ui.current = start
ui.it = b.Iterator()
// Advance to first value >= min
ui.it.AdvanceIfNeeded(min)
// Advance to first value >= start
if start <= MaxUint32 {
ui.it.AdvanceIfNeeded(uint32(start))
}
ui.updateHasNext()
}

Expand All @@ -776,16 +781,16 @@ func (ui *unsetIterator) Next() uint32 {
}

func (ui *unsetIterator) updateHasNext() {
for ui.current <= uint64(ui.max) {
for ui.current < ui.end {
if !ui.it.HasNext() {
// No more set bits, we have values to yield
ui.hasNext = true
return
}

nextSet := ui.it.PeekNext()
if nextSet > ui.max {
// Next set bit is beyond our range, we have values to yield
if uint64(nextSet) >= ui.end {
// Next set bit is at or beyond our range, we have values to yield
ui.hasNext = true
return
}
Expand Down Expand Up @@ -818,8 +823,8 @@ func (ui *unsetIterator) AdvanceIfNeeded(minval uint32) {
return // Already at or past minval
}

if minval > ui.max {
// Beyond our range, no more values
if uint64(minval) >= ui.end {
// At or beyond our range, no more values
ui.hasNext = false
return
}
Expand Down Expand Up @@ -915,11 +920,11 @@ func (rb *Bitmap) ManyIterator() ManyIntIterable {
return p
}

// UnsetIterator creates a new IntPeekable to iterate over values in the range [min, max] that are NOT contained in the bitmap.
// UnsetIterator creates a new IntPeekable to iterate over values in the range [start, end) that are NOT contained in the bitmap.
// The iterator becomes invalid if the bitmap is modified (e.g., with Add or Remove).
func (rb *Bitmap) UnsetIterator(min, max uint32) IntPeekable {
func (rb *Bitmap) UnsetIterator(start, end uint64) IntPeekable {
p := new(unsetIterator)
p.Initialize(rb, min, max)
p.Initialize(rb, start, end)
return p
}

Expand Down
Loading