-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathiterative.go
More file actions
247 lines (221 loc) · 6.11 KB
/
iterative.go
File metadata and controls
247 lines (221 loc) · 6.11 KB
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
package stream
import (
_ "fmt"
)
// Defined a iterator for generic purpose
type Iterator[T any] interface {
/*
Next() returns the next element. If an element is available, val is the element and ok is true.
If an element is not available, val is zero value of the type, and ok is set as false
When OK is false, the value, if returned, should be ignored.
A common way of iterating:
for next, ok := iter.Next(); ok; next, ok = iter.Next() {
do_some_thing_with(next)
}
*/
Next() (result T, ok bool)
}
/*
Utilty struct for array iteration.
Note: Not thread safe
*/
type arrayIterator[T any] struct {
target []T
index int
length int
}
/*
Return a new iterator based on array. target must be an array,
or a slice, or a pointer to an array, or a pointer to a slice
It can't be pointer to pointer to an array/slice
Note: Not thread safe
*/
func NewArrayIterator[T any](target []T) Iterator[T] {
length := len(target)
return &arrayIterator[T]{target, 0, length}
}
/*
Implements Iterator interface
Note: Not thread safe
*/
func (v *arrayIterator[T]) Next() (result T, ok bool) {
if v.index >= v.length {
var zv T
return zv, false
} else {
result := v.target[v.index]
v.index++
return result, true
}
}
// Map entry iteration: Just like java.util.Map.Entry class
type MapEntry[K, V any] struct {
Key K
Value V
}
/*
Utility struct for map key iteration
Note: Not thread safe
*/
type MapKeyIterator[K comparable, V any] struct {
target map[K]V
keys []K
index int
length int
}
/*
Implements Iterator. Returns a map key on each Next() call
All map keys are obtained when iterator is constructed. Thus no new key added after construction
will be returned.
Note: Not thread safe
*/
func (v *MapKeyIterator[K, V]) Next() (result K, ok bool) {
if v.index >= v.length {
var zv K
return zv, false
} else {
k := v.keys[v.index]
v.index++
return k, true
}
}
// Utility struct for map value iteration
//
// Note: Not thread safe
type MapValueIterator[K comparable, V any] struct {
target map[K]V
keys []K
index int
length int
}
// Implements Iterator. Returns a map value on each Next() call
// All map keys are obtained when iterator is constructed. Thus no new key's value added after construction
// will be returned. However, values modified after iteration construction, new value will be returned
// If a value is removed after the iterator was created, the nil value for that key will be returned when iterating
//
// Note: Not thread safe
func (v *MapValueIterator[K, V]) Next() (result V, ok bool) {
if v.index >= v.length {
var zv V
return zv, false
} else {
k := v.keys[v.index]
result = v.target[k]
v.index++
return result, true
}
}
// Utility struct for Map Entry iteration.
// All map keys are obtained when iterator is constructed. Thus no new key's value added after construction
// will be returned. However, values modified after iteration construction, new key/value will be returned
//
// Note: Not thread safe
type MapEntryIterator[K comparable, V any] struct {
target map[K]V
keys []K
index int
length int
}
// Implements Iterator. Will return MapEntry on each call.
//
// Note: Not thread safe
func (v *MapEntryIterator[K, V]) Next() (result MapEntry[K, V], ok bool) {
if v.index >= v.length {
var zv MapEntry[K, V]
return zv, false
} else {
k := v.keys[v.index]
val := v.target[k]
v.index++
return MapEntry[K, V]{k, val}, true
}
}
// Utility struct to for channel iteration
// Iterate through channels requires explicit channel closure. Failing to do so will result
// indefinite waiting.
//
// Note: thread safe
type ChannelIterator[T any] struct {
target chan T
}
// Implements Iterator. result will be channel's corresponding value type, requires casting
//
// Note: thread safe
func (v *ChannelIterator[T]) Next() (result T, ok bool) {
va, okb := <-v.target
if okb {
return va, okb
} else {
var zv T
return zv, okb
}
}
// Collect at most count elements from Iterator object.
// Returns a slice of object collected. If count is 0, empty slice is returned.
// If count is less than 0, Maximum number of objects are collected (similar to Integer.MAX_VALUE in java)
//
// Note: Collected objects might be less than count if Iterator reached end
// Note: Not thread safe
func CollectN[T any](iter Iterator[T], count int) []T {
result := make([]T, 0)
if count == 0 {
return result
}
for next, ok := iter.Next(); ok; next, ok = iter.Next() {
result = append(result, next)
if len(result) >= count && count > 0 {
return result
}
}
return result
}
// Same as CollecctN, but no limit
func CollectAll[T any](iter Iterator[T]) []T {
return CollectN(iter, -1)
}
// Create Iterator on a channel.
// Target must be a channel
//
// Note: Channel sender need to close channel or Iterator's last Next() call will hang forever
// Multiple Iterator on same channel is possible since each Next() call will receive from the channel
func NewChannelIterator[T any](target chan T) *ChannelIterator[T] {
return &ChannelIterator[T]{target}
}
// Create Iterator to iterate over a map's keys.
// Target must be a map or code may panic
// Multiple Iterator on same map is possible
func NewMapKeyIterator[K comparable, V any](target map[K]V) *MapKeyIterator[K, V] {
keys := make([]K, len(target))
var i = 0
for k := range target {
keys[i] = k
i++
}
length := len(keys)
return &MapKeyIterator[K, V]{target, keys, 0, length}
}
// Create Iterator to iterate over a map's values.
// Target must be a map
// Multiple Iterator on same map is possible
func NewMapValueIterator[K comparable, V any](target map[K]V) *MapValueIterator[K, V] {
keys := keys(target)
length := len(keys)
return &MapValueIterator[K, V]{target, keys, 0, length}
}
func keys[K comparable, V any](target map[K]V) []K {
keys := make([]K, len(target))
var i = 0
for k := range target {
keys[i] = k
i++
}
return keys
}
// Create Iterator to iterate over a map's entries
// Target must be a map
// Multiple Iterator on same map is possible.
func NewMapEntryIterator[K comparable, V any](target map[K]V) *MapEntryIterator[K, V] {
keys := keys(target)
length := len(keys)
return &MapEntryIterator[K, V]{target, keys, 0, length}
}