-
Notifications
You must be signed in to change notification settings - Fork 5
/
iterator.go
165 lines (142 loc) · 3.29 KB
/
iterator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package main
import "math/rand"
const NumItems int = 1000000
// Plain int array tests how quickly we can iterate over cache-coherent data
var int_data []int = make([]int, NumItems)
func InitInts() {
for i := 0; i < NumItems; i++ {
int_data[i] = rand.Int()
}
}
// Iterating over the data in a list of pointers tests data that isn't
// cache coherent (following the references ruins the coherency)
type Data struct {
// This intentionally contains more than just an int so it may
// not be as conveniently size if allocations end up in order.
foo int
bar *Data
}
var struct_data []*Data = make([]*Data, NumItems)
func InitData() {
for i := 0; i < NumItems; i++ {
struct_data[i] = &Data{foo: rand.Int(), bar: nil}
}
}
// These are the different types of iterators:
// Callbacks:
func IntCallbackIterator(cb func(int)) {
for _, val := range int_data {
cb(val)
}
}
func DataCallbackIterator(cb func(int)) {
for _, val := range struct_data {
cb(val.foo)
}
}
// Channels:
func IntChannelIterator() <-chan int {
ch := make(chan int)
go func() {
for _, val := range int_data {
ch <- val
}
close(ch)
}()
return ch
}
func DataChannelIterator() <-chan int {
ch := make(chan int)
go func() {
for _, val := range struct_data {
ch <- val.foo
}
close(ch)
}()
return ch
}
// Buffered Channels:
const ChannelBuffer int = 50
func IntBufferedChannelIterator() <-chan int {
ch := make(chan int, ChannelBuffer)
go func() {
for _, val := range int_data {
ch <- val
}
close(ch)
}()
return ch
}
func DataBufferedChannelIterator() <-chan int {
ch := make(chan int, ChannelBuffer)
go func() {
for _, val := range struct_data {
ch <- val.foo
}
close(ch)
}()
return ch
}
// Closures: Return (next(), has_next), where next() returns (val, has_next)
func IntClosureIterator() (func() (int, bool), bool) {
var idx int = 0
var data_len = len(int_data)
return func() (int, bool) {
prev_idx := idx
idx++
return int_data[prev_idx], (idx < data_len)
}, (idx < data_len)
}
func DataClosureIterator() (func() (int, bool), bool) {
var idx int = 0
var data_len = len(struct_data)
return func() (int, bool) {
prev_idx := idx
idx++
return struct_data[prev_idx].foo, (idx < data_len)
}, (idx < data_len)
}
type StatefulIterator interface {
Value() int
Next() bool
}
type dataStatefulIterator struct {
current int
data []*Data
}
func NewDataStatefulIterator(data []*Data) *dataStatefulIterator {
return &dataStatefulIterator{data: data, current: -1}
}
func NewDataStatefulIteratorInterface(data []*Data) StatefulIterator {
return &dataStatefulIterator{data: data, current: -1}
}
func (it *dataStatefulIterator) Value() int {
return it.data[it.current].foo
}
func (it *dataStatefulIterator) Next() bool {
it.current++
if it.current >= len(it.data) {
return false
}
return true
}
type intStatefulIterator struct {
current int
data []int
}
func (it *intStatefulIterator) Value() int {
return it.data[it.current]
}
func (it *intStatefulIterator) Next() bool {
it.current++
if it.current >= len(it.data) {
return false
}
return true
}
func NewIntStatefulIterator(data []int) *intStatefulIterator {
return &intStatefulIterator{data: data, current: -1}
}
func NewIntStatefulIteratorInterface(data []int) StatefulIterator {
return &intStatefulIterator{data: data, current: -1}
}