Skip to content

Commit 57d9a62

Browse files
committed
save
1 parent 0dfbcec commit 57d9a62

2 files changed

Lines changed: 102 additions & 12 deletions

File tree

roaring64/iterables64.go

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ type intIterator struct {
2525
hs uint64
2626
iter roaring.IntPeekable
2727
highlowcontainer *roaringArray64
28+
29+
// These embedded iterators per container type help reduce load in the GC.
30+
// This way, instead of making up-to 4 billion allocations per full iteration
31+
// we get a single allocation and simply reinitialize the embedded iterator
32+
// and point to it in the generic `iter` member on each key bound.
33+
bitmapIter roaring.IntIterator
2834
}
2935

3036
// HasNext returns true if there are more integers to iterate over
@@ -34,8 +40,9 @@ func (ii *intIterator) HasNext() bool {
3440

3541
func (ii *intIterator) init() {
3642
if ii.highlowcontainer.size() > ii.pos {
37-
ii.iter = ii.highlowcontainer.getContainerAtIndex(ii.pos).Iterator()
3843
ii.hs = uint64(ii.highlowcontainer.getKeyAtIndex(ii.pos)) << 32
44+
ii.bitmapIter.Initialize(ii.highlowcontainer.getContainerAtIndex(ii.pos))
45+
ii.iter = &ii.bitmapIter
3946
}
4047
}
4148

@@ -74,11 +81,21 @@ func (ii *intIterator) AdvanceIfNeeded(minval uint64) {
7481
}
7582
}
7683

84+
// IntIterator64 is meant to allow you to iterate through the values of a bitmap, see Initialize(a *Bitmap)
85+
type IntIterator64 = intIterator
86+
87+
// Initialize configures the existing iterator so that it can iterate through the values of
88+
// the provided bitmap.
89+
// The iteration results are undefined if the bitmap is modified (e.g., with Add or Remove).
90+
func (ii *intIterator) Initialize(a *Bitmap) {
91+
ii.pos = 0
92+
ii.highlowcontainer = &a.highlowcontainer
93+
ii.init()
94+
}
95+
7796
func newIntIterator(a *Bitmap) *intIterator {
7897
p := new(intIterator)
79-
p.pos = 0
80-
p.highlowcontainer = &a.highlowcontainer
81-
p.init()
98+
p.Initialize(a)
8299
return p
83100
}
84101

@@ -87,6 +104,9 @@ type intReverseIterator struct {
87104
hs uint64
88105
iter roaring.IntIterable
89106
highlowcontainer *roaringArray64
107+
108+
// Stack-allocated embedded iterator to reduce GC pressure.
109+
bitmapIter roaring.IntReverseIterator
90110
}
91111

92112
// HasNext returns true if there are more integers to iterate over
@@ -96,8 +116,9 @@ func (ii *intReverseIterator) HasNext() bool {
96116

97117
func (ii *intReverseIterator) init() {
98118
if ii.pos >= 0 {
99-
ii.iter = ii.highlowcontainer.getContainerAtIndex(ii.pos).ReverseIterator()
100119
ii.hs = uint64(ii.highlowcontainer.getKeyAtIndex(ii.pos)) << 32
120+
ii.bitmapIter.Initialize(ii.highlowcontainer.getContainerAtIndex(ii.pos))
121+
ii.iter = &ii.bitmapIter
101122
} else {
102123
ii.iter = nil
103124
}
@@ -113,11 +134,21 @@ func (ii *intReverseIterator) Next() uint64 {
113134
return x
114135
}
115136

137+
// IntReverseIterator64 is meant to allow you to iterate through the values of a bitmap in reverse, see Initialize(a *Bitmap)
138+
type IntReverseIterator64 = intReverseIterator
139+
140+
// Initialize configures the existing iterator so that it can iterate through the values of
141+
// the provided bitmap in reverse.
142+
// The iteration results are undefined if the bitmap is modified (e.g., with Add or Remove).
143+
func (ii *intReverseIterator) Initialize(a *Bitmap) {
144+
ii.highlowcontainer = &a.highlowcontainer
145+
ii.pos = a.highlowcontainer.size() - 1
146+
ii.init()
147+
}
148+
116149
func newIntReverseIterator(a *Bitmap) *intReverseIterator {
117150
p := new(intReverseIterator)
118-
p.highlowcontainer = &a.highlowcontainer
119-
p.pos = a.highlowcontainer.size() - 1
120-
p.init()
151+
p.Initialize(a)
121152
return p
122153
}
123154

@@ -132,12 +163,16 @@ type manyIntIterator struct {
132163
hs uint64
133164
iter roaring.ManyIntIterable
134165
highlowcontainer *roaringArray64
166+
167+
// Stack-allocated embedded iterator to reduce GC pressure.
168+
bitmapIter roaring.ManyIntIterator
135169
}
136170

137171
func (ii *manyIntIterator) init() {
138172
if ii.highlowcontainer.size() > ii.pos {
139-
ii.iter = ii.highlowcontainer.getContainerAtIndex(ii.pos).ManyIterator()
140173
ii.hs = uint64(ii.highlowcontainer.getKeyAtIndex(ii.pos)) << 32
174+
ii.bitmapIter.Initialize(ii.highlowcontainer.getContainerAtIndex(ii.pos))
175+
ii.iter = &ii.bitmapIter
141176
} else {
142177
ii.iter = nil
143178
}
@@ -160,10 +195,20 @@ func (ii *manyIntIterator) NextMany(buf []uint64) int {
160195
return n
161196
}
162197

198+
// ManyIntIterator64 is meant to allow you to iterate through the values of a bitmap, see Initialize(a *Bitmap)
199+
type ManyIntIterator64 = manyIntIterator
200+
201+
// Initialize configures the existing iterator so that it can iterate through the values of
202+
// the provided bitmap.
203+
// The iteration results are undefined if the bitmap is modified (e.g., with Add or Remove).
204+
func (ii *manyIntIterator) Initialize(a *Bitmap) {
205+
ii.pos = 0
206+
ii.highlowcontainer = &a.highlowcontainer
207+
ii.init()
208+
}
209+
163210
func newManyIntIterator(a *Bitmap) *manyIntIterator {
164211
p := new(manyIntIterator)
165-
p.pos = 0
166-
p.highlowcontainer = &a.highlowcontainer
167-
p.init()
212+
p.Initialize(a)
168213
return p
169214
}

roaring64/iterables64_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,48 @@ func TestIteratorAdvance(t *testing.T) {
180180
assert.EqualValues(t, 31, i.PeekNext())
181181
})
182182
}
183+
184+
func TestIteratorInitialize(t *testing.T) {
185+
values := []uint64{0, 2, 15, 16, 31, 32, 33, 9999, roaring.MaxUint16, roaring.MaxUint32, roaring.MaxUint32 * 2, math.MaxUint64}
186+
bm := New()
187+
for _, v := range values {
188+
bm.Add(v)
189+
}
190+
191+
t.Run("IntIterator64 stack-allocated", func(t *testing.T) {
192+
var it IntIterator64
193+
it.Initialize(bm)
194+
n := 0
195+
for it.HasNext() {
196+
assert.Equal(t, values[n], it.Next())
197+
n++
198+
}
199+
assert.Equal(t, len(values), n)
200+
})
201+
202+
t.Run("IntReverseIterator64 stack-allocated", func(t *testing.T) {
203+
var it IntReverseIterator64
204+
it.Initialize(bm)
205+
n := len(values) - 1
206+
for it.HasNext() {
207+
assert.Equal(t, values[n], it.Next())
208+
n--
209+
}
210+
assert.Equal(t, -1, n)
211+
})
212+
213+
t.Run("ManyIntIterator64 stack-allocated", func(t *testing.T) {
214+
var it ManyIntIterator64
215+
it.Initialize(bm)
216+
buf := make([]uint64, 4)
217+
var got []uint64
218+
for {
219+
n := it.NextMany(buf)
220+
if n == 0 {
221+
break
222+
}
223+
got = append(got, buf[:n]...)
224+
}
225+
assert.Equal(t, values, got)
226+
})
227+
}

0 commit comments

Comments
 (0)