Skip to content

Commit 6d3d113

Browse files
authored
Merge pull request #524 from e2b-dev/efficient-range-iteration
fix: Ranges() infinite loop on bitmap containers
2 parents 6d1c0c8 + 60ea6a7 commit 6d3d113

File tree

2 files changed

+680
-54
lines changed

2 files changed

+680
-54
lines changed

iter.go

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -92,36 +92,43 @@ func (b *Bitmap) Ranges() iter.Seq2[uint32, uint64] {
9292
pos := uint(0)
9393

9494
for pos < length {
95-
if bm[pos] == 0 {
95+
w := bm[pos]
96+
if w == 0 {
9697
pos++
9798
continue
9899
}
99100

100-
w := bm[pos]
101-
lo := uint(countTrailingZeros(w))
102-
bitStart := pos*64 + lo
101+
for w != 0 {
102+
lo := uint(countTrailingZeros(w))
103+
bitStart := pos*64 + lo
103104

104-
ones := uint(countTrailingOnes(w >> lo))
105-
if lo+ones < 64 {
106-
if !emit(hs|uint64(bitStart), hs|uint64(bitStart+ones)) {
107-
return
108-
}
109-
pos = (bitStart + ones) / 64
110-
} else {
111-
pos++
112-
for pos < length && bm[pos] == 0xFFFFFFFFFFFFFFFF {
113-
pos++
114-
}
115-
var bitEnd uint
116-
if pos < length {
117-
bitEnd = pos*64 + uint(countTrailingOnes(bm[pos]))
105+
ones := uint(countTrailingOnes(w >> lo))
106+
if lo+ones < 64 {
107+
if !emit(hs+uint64(bitStart), hs+uint64(bitStart+ones)) {
108+
return
109+
}
110+
w &= ^((uint64(1) << (lo + ones)) - 1)
118111
} else {
119-
bitEnd = length * 64
120-
}
121-
if !emit(hs|uint64(bitStart), hs|uint64(bitEnd)) {
122-
return
112+
pos++
113+
for pos < length && bm[pos] == 0xFFFFFFFFFFFFFFFF {
114+
pos++
115+
}
116+
var bitEnd uint
117+
if pos < length {
118+
trailing := uint(countTrailingOnes(bm[pos]))
119+
bitEnd = pos*64 + trailing
120+
w = bm[pos] & ^((uint64(1) << trailing) - 1)
121+
} else {
122+
bitEnd = length * 64
123+
w = 0
124+
}
125+
if !emit(hs+uint64(bitStart), hs+uint64(bitEnd)) {
126+
return
127+
}
128+
continue
123129
}
124130
}
131+
pos++
125132
}
126133

127134
case *arrayContainer:
@@ -135,7 +142,7 @@ func (b *Bitmap) Ranges() iter.Seq2[uint32, uint64] {
135142
end++
136143
i++
137144
}
138-
if !emit(hs|start, hs|end) {
145+
if !emit(hs+start, hs+end) {
139146
return
140147
}
141148
}

0 commit comments

Comments
 (0)