-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathiterator.go
173 lines (158 loc) · 4.4 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
166
167
168
169
170
171
172
173
package collection
// Iterator is a lazy iterator over generic data types.
// It can be called several times to produce values.
// When the second returned value is `true` means the value is valid and it can be consumed.
// When the second returned value is `false` means the value is not valid.
// In this case the zero value of the type `T` is returned and it should not be consumed.
// Consecutive calls after the first time `false` is returned, should return the same values.
//
// Iterator is not limited to the structures defined in this package. The source of the iterated values can be anything.
// Ex: think of iterating over the lines of a file without having to load the whole file into memory, or iterating over the cursor of a database.
type Iterator[T any] func() (T, bool)
// Any returns true as soon as a value satisfies the test, false otherwise.
func (it Iterator[T]) Any(test func(item T) bool) bool {
for i, ok := it(); ok; i, ok = it() {
if test(i) {
return true
}
}
return false
}
// Collect will consume the iterator and return a `Vec` with all the values.
func (it Iterator[T]) Collect() Vec[T] {
var vec Vec[T]
for i, ok := it(); ok; i, ok = it() {
vec = append(vec, i)
}
return vec
}
// Count will consume the iterator and return the number of values iterated.
func (it Iterator[T]) Count() int {
var c int
for _, ok := it(); ok; _, ok = it() {
c++
}
return c
}
// Every will return false as soon as a value will fail the test, true otherwise.
func (it Iterator[T]) Every(test func(item T) bool) bool {
for i, ok := it(); ok; i, ok = it() {
if !test(i) {
return false
}
}
return true
}
// Filter will pass only the values that satisfy the test.
func (it Iterator[T]) Filter(test func(item T) bool) Iterator[T] {
return func() (T, bool) {
for i, ok := it(); ok; i, ok = it() {
if test(i) {
return i, ok
}
}
return *new(T), false
}
}
// Find will try to find a value that satisfies the test.
// The second returned value is true if a value was found, false otherwise.
func (it Iterator[T]) Find(test func(item T) bool) (T, bool) {
for i, ok := it(); ok; i, ok = it() {
if test(i) {
return i, ok
}
}
return *new(T), false
}
// FollowedBy will yield first the values of `it` followed by the values of `other`.
func (it Iterator[T]) FollowedBy(other Iterator[T]) Iterator[T] {
other_turn := false
return func() (T, bool) {
if other_turn {
return other()
}
if i, ok := it(); ok {
return i, ok
}
other_turn = true
return other()
}
}
// ForEach will consume the iterator and run the action with every value.
func (it Iterator[T]) ForEach(action func(item T)) {
for i, ok := it(); ok; i, ok = it() {
action(i)
}
}
// Skip will skip the first `count` values
func (it Iterator[T]) Skip(count int) Iterator[T] {
skipped := false
return func() (T, bool) {
if skipped {
return it()
}
for i := 0; i < count; i++ {
if _, ok := it(); !ok {
skipped = true
return *new(T), false
}
}
skipped = true
return it()
}
}
// SkipWhile will skip the first elements that satisfy the test.
func (it Iterator[T]) SkipWhile(test func(item T) bool) Iterator[T] {
skipped := false
return func() (T, bool) {
if !skipped {
skipped = true
return it.Find(func(item T) bool { return !test(item) })
}
return it()
}
}
// Take will yield at most the first `count` values.
func (it Iterator[T]) Take(count int) Iterator[T] {
taken := 0
return func() (T, bool) {
if taken >= count {
return *new(T), false
}
if i, ok := it(); ok {
taken++
return i, ok
}
taken = count
return *new(T), false
}
}
// TakeWhile will stop at the first value that does not satisfy the test.
func (it Iterator[T]) TakeWhile(test func(item T) bool) Iterator[T] {
stopped := false
return func() (T, bool) {
if stopped {
return *new(T), false
}
if i, ok := it(); ok && test(i) {
return i, ok
}
stopped = true
return *new(T), false
}
}
// Tap will run `action` with every value that will pass through the iterator.
func (it Iterator[T]) Tap(action func(item T)) Iterator[T] {
return func() (T, bool) {
i, ok := it()
if ok {
action(i)
}
return i, ok
}
}
// Reverse will consume the iterator, collect the values in a `Vec` and iterate in reverse those values.
// Since `Reverse` will consume the iterator and allocate a `Vec`, when possible use `Vec.ReverseIter`.
func (it Iterator[T]) Reverse() Iterator[T] {
return it.Collect().ReverseIter()
}