-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstream.go
105 lines (94 loc) · 1.64 KB
/
stream.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
package kana
import (
"strings"
"unicode/utf8"
)
type stream struct {
buf []rune
end bool
next func(buf *[]rune)
}
func (s *stream) fill(demand int) {
if s.end {
return
}
for len(s.buf) < demand {
oldSize := len(s.buf)
s.next(&s.buf)
if len(s.buf) == oldSize {
s.end = true
break
}
}
}
func (s *stream) consume(num int) {
newSize := len(s.buf) - num
for i := 0; i < newSize; i++ {
s.buf[i] = s.buf[i+num]
}
s.buf = s.buf[:newSize]
}
func (s *stream) readOne() (rune, bool) {
s.fill(1)
if len(s.buf) == 0 {
return 0, false
}
ch := s.buf[0]
s.consume(1)
return ch, true
}
func (s *stream) peekOne() (rune, bool) {
s.fill(1)
if len(s.buf) == 0 {
return 0, false
}
return s.buf[0], true
}
func (s *stream) readAll() string {
builder := strings.Builder{}
if !s.end {
for {
s.readCurrentTo(&builder)
oldSize := len(s.buf)
s.next(&s.buf)
if len(s.buf) == oldSize {
s.end = true
break
}
}
}
s.readCurrentTo(&builder)
return builder.String()
}
func (s *stream) readCurrentTo(builder *strings.Builder) {
for _, ch := range s.buf {
builder.WriteRune(ch)
}
s.buf = s.buf[:0]
}
func newStream(next func(buf *[]rune)) *stream {
return &stream{
buf: nil,
end: false,
next: next,
}
}
func stringStream(s string) *stream {
pos := 0
return newStream(func(buf *[]rune) {
if pos < len(s) {
ch, size := utf8.DecodeRuneInString(s[pos:])
*buf = append(*buf, ch)
pos += size
}
})
}
func mapStream(s *stream, f func(rune) rune) *stream {
return newStream(func(buf *[]rune) {
s.fill(1)
for _, ch := range s.buf {
*buf = append(*buf, f(ch))
}
s.consume(len(s.buf))
})
}