-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathiterator.go
151 lines (130 loc) · 3.15 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
package runes
import "github.com/diegommm/runes/iface"
type Iterator = iface.Iterator
func ExpandIterator(i Iterator) []rune {
ret := make([]rune, 0, i.RuneLen())
for {
r, ok := i.NextRune()
if !ok {
break
}
ret = append(ret, r)
}
return ret
}
// RunesIterator returns an iterator from the given slice of runes, which must
// be in sorted ascending order and non-repeating.
func RunesIterator(rs []rune) Iterator {
if len(rs) > maxInt32 {
panic("RunesIterator: too many runes")
}
return &runesIterator{rs: rs}
}
type runesIterator struct {
rs []rune
pos uint32
}
func (x *runesIterator) NextRune() (rune, bool) {
if pos := int(x.pos); pos < len(x.rs) {
x.pos++
return x.rs[pos], true
}
return 0, false
}
func (x *runesIterator) Max() rune {
if len(x.rs) > 0 {
return x.rs[len(x.rs)-1]
}
return -1
}
func (x *runesIterator) RuneLen() int32 { return int32(len(x.rs)) }
func (x *runesIterator) Restart() { x.pos = 0 }
// RuneReader is the standard library's [io.RuneReader] interface.
type RuneReader interface {
ReadRune() (r rune, size int, err error)
}
// ReadAllRunes returns all the runes read from the given [RuneReader]. It stops
// at the first error.
func ReadAllRunes(rr RuneReader) []rune {
var l int
if rrl, ok := rr.(interface{ Len() int }); ok {
l = rrl.Len() // we will have at most this amount of runes
}
rs := make([]rune, 0, l)
for {
r, _, err := rr.ReadRune()
if err != nil {
break
}
rs = append(rs, r)
}
return rs
}
// RangeIterator returns an [Iterator] from the given [Range].
func RangeIterator(r Range) Iterator {
return &rangeIterator{r: r}
}
type rangeIterator struct {
r Range
pos int32
}
func (x *rangeIterator) NextRune() (rune, bool) {
if r := x.r.Nth(x.pos); r >= 0 {
x.pos++
return r, true
}
return 0, false
}
func (x *rangeIterator) RuneLen() int32 { return x.r.RuneLen() - x.pos }
func (x *rangeIterator) Max() rune { return x.r.Max() }
func (x *rangeIterator) Restart() { x.pos = 0 }
// Merge merges multiple [Range] values into a single iterator.
func Merge(rs ...Range) Iterator {
is := make([]Iterator, len(rs))
for i := range rs {
is[i] = RangeIterator(rs[i])
}
return MergeIterators(is...)
}
// MergeIterators merges multiple iterators in a consistent manner.
func MergeIterators(is ...Iterator) Iterator {
var l int32
for i := range is {
l += is[i].RuneLen()
}
rs := make([]rune, 0, l) // we will have at most `l` runes
// initialize list of iterators runes
isRunes := make([]rune, 0, len(is))
for i := len(is) - 1; i >= 0; i-- {
r, ok := is[i].NextRune()
if !ok {
removeAtIndex(&is, i)
continue
}
isRunes = append(isRunes, r)
}
for len(isRunes) > 0 {
// find the smallest rune and append it to our list
var minIdx int
minRune := isRunes[minIdx]
for i, r := range isRunes {
if r < minRune {
minRune, minIdx = r, i
}
}
rs = append(rs, minRune)
// prune the smallest rune
for i := len(isRunes) - 1; i >= minIdx; i-- {
if isRunes[i] == minRune {
r, ok := is[i].NextRune()
if !ok {
removeAtIndex(&is, i)
removeAtIndex(&isRunes, i)
continue
}
isRunes[i] = r
}
}
}
return RunesIterator(rs)
}