Skip to content

Commit 2893d51

Browse files
authored
Merge pull request #475 from amikai/go-1.23-iterator
Support 1.23 iterator in a backward-compatible way
2 parents 09c46a0 + 69146ec commit 2893d51

File tree

5 files changed

+445
-0
lines changed

5 files changed

+445
-0
lines changed

benchmark123_test.go

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
//go:build go1.23
2+
// +build go1.23
3+
4+
package roaring
5+
6+
import (
7+
"math/rand"
8+
"testing"
9+
)
10+
11+
func BenchmarkIterator123(b *testing.B) {
12+
bm := NewBitmap()
13+
domain := 100000000
14+
count := 10000
15+
for j := 0; j < count; j++ {
16+
v := uint32(rand.Intn(domain))
17+
bm.Add(v)
18+
}
19+
i := IntIterator{}
20+
expectedCardinality := bm.GetCardinality()
21+
counter := uint64(0)
22+
23+
b.Run("simple iteration with alloc", func(b *testing.B) {
24+
for n := 0; n < b.N; n++ {
25+
counter = 0
26+
i := bm.Iterator()
27+
for i.HasNext() {
28+
i.Next()
29+
counter++
30+
}
31+
}
32+
b.StopTimer()
33+
})
34+
if counter != expectedCardinality {
35+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
36+
}
37+
b.Run("simple iteration", func(b *testing.B) {
38+
for n := 0; n < b.N; n++ {
39+
counter = 0
40+
i.Initialize(bm)
41+
for i.HasNext() {
42+
i.Next()
43+
counter++
44+
}
45+
}
46+
b.StopTimer()
47+
})
48+
if counter != expectedCardinality {
49+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
50+
}
51+
b.Run("values iteration", func(b *testing.B) {
52+
for n := 0; n < b.N; n++ {
53+
counter = 0
54+
Values(bm)(func(_ uint32) bool {
55+
counter++
56+
return true
57+
})
58+
}
59+
b.StopTimer()
60+
})
61+
if counter != expectedCardinality {
62+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
63+
}
64+
b.Run("reverse iteration with alloc", func(b *testing.B) {
65+
for n := 0; n < b.N; n++ {
66+
counter = 0
67+
ir := bm.ReverseIterator()
68+
for ir.HasNext() {
69+
ir.Next()
70+
counter++
71+
}
72+
}
73+
b.StopTimer()
74+
})
75+
if counter != expectedCardinality {
76+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
77+
}
78+
ir := IntReverseIterator{}
79+
80+
b.Run("reverse iteration", func(b *testing.B) {
81+
for n := 0; n < b.N; n++ {
82+
counter = 0
83+
ir.Initialize(bm)
84+
for ir.HasNext() {
85+
ir.Next()
86+
counter++
87+
}
88+
}
89+
b.StopTimer()
90+
})
91+
if counter != expectedCardinality {
92+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
93+
}
94+
b.Run("backward iteration", func(b *testing.B) {
95+
for n := 0; n < b.N; n++ {
96+
counter = 0
97+
Backward(bm)(func(_ uint32) bool {
98+
counter++
99+
return true
100+
})
101+
}
102+
b.StopTimer()
103+
})
104+
if counter != expectedCardinality {
105+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
106+
}
107+
108+
b.Run("many iteration with alloc", func(b *testing.B) {
109+
for n := 0; n < b.N; n++ {
110+
counter = 0
111+
buf := make([]uint32, 1024)
112+
im := bm.ManyIterator()
113+
for n := im.NextMany(buf); n != 0; n = im.NextMany(buf) {
114+
counter += uint64(n)
115+
}
116+
}
117+
b.StopTimer()
118+
})
119+
if counter != expectedCardinality {
120+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
121+
}
122+
im := ManyIntIterator{}
123+
buf := make([]uint32, 1024)
124+
125+
b.Run("many iteration", func(b *testing.B) {
126+
for n := 0; n < b.N; n++ {
127+
counter = 0
128+
im.Initialize(bm)
129+
for n := im.NextMany(buf); n != 0; n = im.NextMany(buf) {
130+
counter += uint64(n)
131+
}
132+
}
133+
b.StopTimer()
134+
})
135+
if counter != expectedCardinality {
136+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
137+
}
138+
139+
b.Run("values iteration 1.23", func(b *testing.B) {
140+
for n := 0; n < b.N; n++ {
141+
counter = 0
142+
for range Values(bm) {
143+
counter++
144+
}
145+
}
146+
b.StopTimer()
147+
})
148+
if counter != expectedCardinality {
149+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
150+
}
151+
152+
b.Run("backward iteration 1.23", func(b *testing.B) {
153+
for n := 0; n < b.N; n++ {
154+
counter = 0
155+
for range Backward(bm) {
156+
counter++
157+
}
158+
}
159+
b.StopTimer()
160+
})
161+
if counter != expectedCardinality {
162+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
163+
}
164+
}

benchmark_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,19 @@ func BenchmarkIteratorAlloc(b *testing.B) {
5454
if counter != expectedCardinality {
5555
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
5656
}
57+
b.Run("values iteration", func(b *testing.B) {
58+
for n := 0; n < b.N; n++ {
59+
counter = 0
60+
Values(bm)(func(_ uint32) bool {
61+
counter++
62+
return true
63+
})
64+
}
65+
b.StopTimer()
66+
})
67+
if counter != expectedCardinality {
68+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
69+
}
5770
b.Run("reverse iteration with alloc", func(b *testing.B) {
5871
for n := 0; n < b.N; n++ {
5972
counter = 0
@@ -84,6 +97,19 @@ func BenchmarkIteratorAlloc(b *testing.B) {
8497
if counter != expectedCardinality {
8598
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
8699
}
100+
b.Run("backward iteration", func(b *testing.B) {
101+
for n := 0; n < b.N; n++ {
102+
counter = 0
103+
Backward(bm)(func(_ uint32) bool {
104+
counter++
105+
return true
106+
})
107+
}
108+
b.StopTimer()
109+
})
110+
if counter != expectedCardinality {
111+
b.Fatalf("Cardinalities don't match: %d, %d", counter, expectedCardinality)
112+
}
87113

88114
b.Run("many iteration with alloc", func(b *testing.B) {
89115
for n := 0; n < b.N; n++ {

iter.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package roaring
2+
3+
func Values(b *Bitmap) func(func(uint32) bool) {
4+
return func(yield func(uint32) bool) {
5+
it := b.Iterator()
6+
for it.HasNext() {
7+
if !yield(it.Next()) {
8+
return
9+
}
10+
}
11+
}
12+
}
13+
14+
func Backward(b *Bitmap) func(func(uint32) bool) {
15+
return func(yield func(uint32) bool) {
16+
it := b.ReverseIterator()
17+
for it.HasNext() {
18+
if !yield(it.Next()) {
19+
return
20+
}
21+
}
22+
}
23+
}

iter123_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//go:build go1.23
2+
// +build go1.23
3+
4+
package roaring
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestBackwardCount123(t *testing.T) {
13+
array := []int{2, 63, 64, 65, 4095, 4096, 4097, 4159, 4160, 4161, 5000, 20000, 66666}
14+
for _, testSize := range array {
15+
b := New()
16+
for i := uint32(0); i < uint32(testSize); i++ {
17+
b.Add(i)
18+
}
19+
20+
count := 0
21+
for range Values(b) {
22+
count++
23+
}
24+
25+
assert.Equal(t, testSize, count)
26+
}
27+
}
28+
29+
func TestBackward123(t *testing.T) {
30+
t.Run("#1", func(t *testing.T) {
31+
values := []uint32{0, 2, 15, 16, 31, 32, 33, 9999, MaxUint16, MaxUint32}
32+
b := New()
33+
for n := 0; n < len(values); n++ {
34+
b.Add(values[n])
35+
}
36+
n := len(values) - 1
37+
for val := range Backward(b) {
38+
assert.EqualValues(t, val, values[n])
39+
n--
40+
}
41+
})
42+
43+
t.Run("#2", func(t *testing.T) {
44+
b := New()
45+
46+
count := 0
47+
for range Backward(b) {
48+
count++
49+
}
50+
51+
assert.Equal(t, 0, count)
52+
})
53+
54+
t.Run("#3", func(t *testing.T) {
55+
b := New()
56+
b.AddInt(0)
57+
58+
// only one value zero
59+
for val := range Backward(b) {
60+
assert.EqualValues(t, 0, val)
61+
}
62+
})
63+
64+
t.Run("#4", func(t *testing.T) {
65+
b := New()
66+
b.AddInt(9999)
67+
68+
// only one value 9999
69+
for val := range Backward(b) {
70+
assert.EqualValues(t, 9999, val)
71+
}
72+
})
73+
74+
t.Run("#5", func(t *testing.T) {
75+
b := New()
76+
b.AddInt(MaxUint16)
77+
78+
// only one value MaxUint16
79+
for val := range Backward(b) {
80+
assert.EqualValues(t, MaxUint16, val)
81+
}
82+
})
83+
84+
t.Run("#6", func(t *testing.T) {
85+
b := New()
86+
b.AddInt(MaxUint32)
87+
88+
// only one value MaxUint32
89+
for val := range Backward(b) {
90+
assert.EqualValues(t, MaxUint32, val)
91+
}
92+
})
93+
}
94+
95+
func TestValues123(t *testing.T) {
96+
b := New()
97+
98+
testSize := 5000
99+
for i := 0; i < testSize; i++ {
100+
b.AddInt(i)
101+
}
102+
103+
n := 0
104+
for val := range Values(b) {
105+
assert.Equal(t, uint32(n), val)
106+
n++
107+
108+
}
109+
110+
assert.Equal(t, testSize, n)
111+
}

0 commit comments

Comments
 (0)