-
Notifications
You must be signed in to change notification settings - Fork 39
/
range.go
70 lines (57 loc) · 1.51 KB
/
range.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
package producer
import (
"context"
"fmt"
"strconv"
)
// Range defines a range of values which should be tested.
type Range struct {
First, Last int
}
// ParseRange parses a range from the string s. Valid formats are `n` and `n-m`.
func ParseRange(s string) (r Range, err error) {
// test if it's a number only
n, err := strconv.Atoi(s)
if err == nil {
return Range{First: n, Last: n}, nil
}
// otherwise assume it's a range
_, err = fmt.Sscanf(s, "%d-%d", &r.First, &r.Last)
if err != nil {
return Range{}, fmt.Errorf("wrong format for range, expected: first-last, got: %q", s)
}
if r.First > r.Last {
return Range{}, fmt.Errorf("last value is smaller than first value for range %q", s)
}
return r, nil
}
// Count returns the number of items in the range.
func (r Range) Count() int {
return r.Last - r.First + 1
}
// Ranges sends all range values to the channel ch, and the number of items to
// the channel count. Sending stops and ch and count are closed when an error
// occurs or the context is cancelled. When format is the empty string, "%d% is
// used.
func Ranges(ctx context.Context, ranges []Range, format string, ch chan<- string, count chan<- int) error {
if format == "" {
format = "%d"
}
var fullcount int
for _, r := range ranges {
fullcount += r.Count()
}
count <- fullcount
defer close(ch)
for _, r := range ranges {
for i := r.First; i <= r.Last; i++ {
v := fmt.Sprintf(format, i)
select {
case ch <- v:
case <-ctx.Done():
return nil
}
}
}
return nil
}