-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathsource.go
More file actions
286 lines (260 loc) · 6.72 KB
/
source.go
File metadata and controls
286 lines (260 loc) · 6.72 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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
package xiter
import (
"context"
"io"
"iter"
"slices"
"strings"
"unicode"
"unicode/utf8"
"unsafe"
)
// Generate returns a Seq that first yields start and then yields
// successive values by adding step to the previous continuously. The
// returned Seq does not end. To limit it to a specific number of
// returned elements, use [Limit].
func Generate[T Addable](start, step T) iter.Seq[T] {
return func(yield func(T) bool) {
for {
if !yield(start) {
return
}
start += step
}
}
}
// Of returns a Seq that yields the provided values.
func Of[T any](vals ...T) iter.Seq[T] {
return slices.Values(vals)
}
// Bytes returns a Seq over the bytes of s.
func Bytes(s string) iter.Seq[byte] {
return func(yield func(byte) bool) {
for i := 0; i < len(s); i++ {
if !yield(s[i]) {
return
}
}
}
}
// Runes returns a Seq over the runes of s.
func Runes[T ~[]byte | ~string](s T) iter.Seq[rune] {
return func(yield func(rune) bool) {
b := unsafe.Slice(unsafe.StringData(*(*string)(unsafe.Pointer(&s))), len(s))
for len(b) > 0 {
r, size := utf8.DecodeRune(b)
if !yield(r) {
return
}
b = b[size:]
}
}
}
// StringSplit returns an iterator over the substrings of s that are
// separated by sep. It behaves very similarly to [strings.Split].
func StringSplit(s, sep string) iter.Seq[string] {
if sep == "" {
return Map(Runes(s), func(c rune) string { return string(c) })
}
return func(yield func(string) bool) {
for {
m := strings.Index(s, sep)
if m < 0 {
yield(s)
return
}
if !yield(s[:m]) {
return
}
s = s[m+len(sep):]
}
}
}
// StringFields returns an iterator over the substrings of s that are
// seperated by consecutive whitespace as determined by
// [unicode.IsSpace]. It is very similar to [strings.Fields].
func StringFields(s string) iter.Seq[string] {
return StringFieldsFunc(s, unicode.IsSpace)
}
// StringFieldsFunc returns an iterator over the substrings of s that
// are seperated by consecutive sections of runes for which sep
// returns true. It behaves very similarly to [strings.FieldsFunc].
func StringFieldsFunc(s string, sep func(rune) bool) iter.Seq[string] {
return func(yield func(string) bool) {
start := 0
for i, r := range Enumerate(Runes(s)) {
if !sep(r) {
continue
}
field := s[start:i]
start = i + 1
if field == "" {
continue
}
if !yield(field) {
return
}
}
field := s[start:]
if field == "" {
return
}
if !yield(field) {
return
}
}
}
// ToPair takes a two-value iterator and produces a single-value
// iterator of pairs.
func ToPair[T1, T2 any](seq iter.Seq2[T1, T2]) iter.Seq[Pair[T1, T2]] {
return func(yield func(Pair[T1, T2]) bool) {
seq(func(v1 T1, v2 T2) bool {
return yield(P(v1, v2))
})
}
}
// V1 returns a Seq which iterates over only the T1 elements of seq.
func V1[T1, T2 any](seq iter.Seq2[T1, T2]) iter.Seq[T1] {
return func(yield func(T1) bool) {
seq(func(v1 T1, v2 T2) bool {
return yield(v1)
})
}
}
// V2 returns a Seq which iterates over only the T2 elements of seq.
func V2[T1, T2 any](seq iter.Seq2[T1, T2]) iter.Seq[T2] {
return func(yield func(T2) bool) {
seq(func(v1 T1, v2 T2) bool {
return yield(v2)
})
}
}
// OfChan returns a Seq which yields values received from c. The
// sequence ends when c is closed. It is equivalent to range c.
func OfChan[T any](c <-chan T) iter.Seq[T] {
return func(yield func(T) bool) {
for v := range c {
if !yield(v) {
return
}
}
}
}
// RecvContext returns a Seq that receives from c continuously until
// either c is closed or the given context is canceled.
func RecvContext[T any](ctx context.Context, c <-chan T) iter.Seq[T] {
return func(yield func(T) bool) {
for {
select {
case <-ctx.Done():
return
case v, ok := <-c:
if !ok || !yield(v) {
return
}
}
}
}
}
// SliceChunksFunc is like [ChunksFunc] but operates on a slice
// instead of an [iter.Seq]. When dealing with data that is in a
// slice, this is more effecient than using ChunksFunc as it can yield
// subslices of the underlying slice instead of having to allocate a
// moving window. The yielded subslices have their capacity clipped.
func SliceChunksFunc[T any, C comparable, S ~[]T](s S, chunker func(T) C) iter.Seq[S] {
return func(yield func(S) bool) {
if len(s) == 0 {
return
}
prev := chunker(s[0])
var start int
for i := 1; i < len(s); i++ {
v := s[i]
cur := chunker(v)
if cur == prev {
continue
}
if !yield(slices.Clip(s[start:i])) {
return
}
prev, start = cur, i
}
last := s[start:]
if len(last) != 0 {
if !yield(slices.Clip(last)) {
return
}
}
}
}
// reader returns an iterator that reads using the given function. If
// that function returns a non-nil error, the iterator will yield that
// error and then exit. If the iterator is terminated early, it will
// call the provided done function first.
func reader[T byte | rune](read func() (T, error), done func()) iter.Seq2[T, error] {
return func(yield func(T, error) bool) {
for {
c, err := read()
if err != nil {
yield(c, err)
return
}
if !yield(c, nil) {
done()
return
}
}
}
}
// ReadBytes returns an iterator over the bytes of r. If reading the
// next byte returns an error, the iterator will yield a non-nil error
// and then exit.
func ReadBytes(r io.ByteReader) iter.Seq2[byte, error] {
return reader(
r.ReadByte,
func() {},
)
}
// ReadRunes returns an iterator over the runes of r. If reading the
// next rune returns an error, the iterator will yield a non-nil error
// and then exit.
func ReadRunes(r io.RuneReader) iter.Seq2[rune, error] {
return reader(
func() (rune, error) {
c, _, err := r.ReadRune()
return c, err
},
func() {},
)
}
// ScanBytes returns an iterator over the bytes of r. If reading the
// next byte returns an error, the iterator will yield a non-nil error
// and then exit.
//
// If the iterator is terminated early, it will unread
// the last byte read, allowing it to be used again to continue from
// where it left off. If this is not the desired behavior, use
// [ReadBytes] instead.
func ScanBytes(r io.ByteScanner) iter.Seq2[byte, error] {
return reader(
r.ReadByte,
func() { r.UnreadByte() },
)
}
// ScanRunes returns an iterator over the runes of r. If reading the
// next rune returns an error, the iterator will yield a non-nil error
// and then exit.
//
// If the iterator is terminated early, it will unread
// the last rune read, allowing it to be used again to continue from
// where it left off. If this is not the desired behavior, use
// [ReadRunes] instead.
func ScanRunes(r io.RuneScanner) iter.Seq2[rune, error] {
return reader(
func() (rune, error) {
c, _, err := r.ReadRune()
return c, err
},
func() { r.UnreadRune() },
)
}