Skip to content

Commit cd3b837

Browse files
committed
pattern: replace bytes.Buffer with strings.Builder
It avoids copying memory one more time when making the resulting string.
1 parent 8a36c1e commit cd3b837

File tree

1 file changed

+36
-37
lines changed

1 file changed

+36
-37
lines changed

pattern/pattern.go

+36-37
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
package pattern
1010

1111
import (
12-
"bytes"
1312
"fmt"
1413
"regexp"
1514
"strconv"
@@ -66,15 +65,15 @@ noopLoop:
6665
return pat, nil
6766
}
6867
closingBraces := []int{}
69-
var buf bytes.Buffer
68+
var sb strings.Builder
7069
// Enable matching `\n` with the `.` metacharacter as globs match `\n`
71-
buf.WriteString("(?s)")
70+
sb.WriteString("(?s)")
7271
dotMeta := false
7372
if mode&NoGlobCase != 0 {
74-
buf.WriteString("(?i)")
73+
sb.WriteString("(?i)")
7574
}
7675
if mode&EntireString != 0 {
77-
buf.WriteString("^")
76+
sb.WriteString("^")
7877
}
7978
writeLoop:
8079
for i := 0; i < len(pat); i++ {
@@ -86,45 +85,45 @@ writeLoop:
8685
if i++; i < len(pat) && pat[i] == '*' {
8786
singleAfter := i == len(pat)-1 || pat[i+1] == '/'
8887
if mode&NoGlobStar != 0 || !singleBefore || !singleAfter {
89-
buf.WriteString("[^/]*")
88+
sb.WriteString("[^/]*")
9089
} else if i++; i < len(pat) && pat[i] == '/' {
91-
buf.WriteString("(.*/|)")
90+
sb.WriteString("(.*/|)")
9291
dotMeta = true
9392
} else {
94-
buf.WriteString(".*")
93+
sb.WriteString(".*")
9594
dotMeta = true
9695
i--
9796
}
9897
} else {
99-
buf.WriteString("[^/]*")
98+
sb.WriteString("[^/]*")
10099
i--
101100
}
102101
} else {
103-
buf.WriteString(".*")
102+
sb.WriteString(".*")
104103
dotMeta = true
105104
}
106105
if mode&Shortest != 0 {
107-
buf.WriteByte('?')
106+
sb.WriteByte('?')
108107
}
109108
case '?':
110109
if mode&Filenames != 0 {
111-
buf.WriteString("[^/]")
110+
sb.WriteString("[^/]")
112111
} else {
113-
buf.WriteByte('.')
112+
sb.WriteByte('.')
114113
dotMeta = true
115114
}
116115
case '\\':
117116
if i++; i >= len(pat) {
118117
return "", &SyntaxError{msg: `\ at end of pattern`}
119118
}
120-
buf.WriteString(regexp.QuoteMeta(string(pat[i])))
119+
sb.WriteString(regexp.QuoteMeta(string(pat[i])))
121120
case '[':
122121
name, err := charClass(pat[i:])
123122
if err != nil {
124123
return "", &SyntaxError{msg: "charClass invalid", err: err}
125124
}
126125
if name != "" {
127-
buf.WriteString(name)
126+
sb.WriteString(name)
128127
i += len(name) - 1
129128
break
130129
}
@@ -133,24 +132,24 @@ writeLoop:
133132
if c == ']' {
134133
break
135134
} else if c == '/' {
136-
buf.WriteString("\\[")
135+
sb.WriteString("\\[")
137136
continue writeLoop
138137
}
139138
}
140139
}
141-
buf.WriteByte(c)
140+
sb.WriteByte(c)
142141
if i++; i >= len(pat) {
143142
return "", &SyntaxError{msg: "[ was not matched with a closing ]"}
144143
}
145144
switch c = pat[i]; c {
146145
case '!', '^':
147-
buf.WriteByte('^')
146+
sb.WriteByte('^')
148147
if i++; i >= len(pat) {
149148
return "", &SyntaxError{msg: "[ was not matched with a closing ]"}
150149
}
151150
}
152151
if c = pat[i]; c == ']' {
153-
buf.WriteByte(']')
152+
sb.WriteByte(']')
154153
if i++; i >= len(pat) {
155154
return "", &SyntaxError{msg: "[ was not matched with a closing ]"}
156155
}
@@ -159,11 +158,11 @@ writeLoop:
159158
loopBracket:
160159
for ; i < len(pat); i++ {
161160
c = pat[i]
162-
buf.WriteByte(c)
161+
sb.WriteByte(c)
163162
switch c {
164163
case '\\':
165164
if i++; i < len(pat) {
166-
buf.WriteByte(pat[i])
165+
sb.WriteByte(pat[i])
167166
}
168167
continue
169168
case ']':
@@ -183,7 +182,7 @@ writeLoop:
183182
}
184183
case '{':
185184
if mode&Braces == 0 {
186-
buf.WriteString(regexp.QuoteMeta(string(c)))
185+
sb.WriteString(regexp.QuoteMeta(string(c)))
187186
break
188187
}
189188
innerLevel := 1
@@ -205,7 +204,7 @@ writeLoop:
205204
break peekBrace
206205
}
207206
closingBraces = append(closingBraces, j)
208-
buf.WriteString("(?:")
207+
sb.WriteString("(?:")
209208
continue writeLoop
210209
}
211210
}
@@ -216,47 +215,47 @@ writeLoop:
216215
return "", &SyntaxError{msg: fmt.Sprintf("invalid range: %q", match[0])}
217216
}
218217
// TODO: can we do better here?
219-
buf.WriteString("(?:")
218+
sb.WriteString("(?:")
220219
for n := start; n <= end; n++ {
221220
if n > start {
222-
buf.WriteByte('|')
221+
sb.WriteByte('|')
223222
}
224-
fmt.Fprintf(&buf, "%d", n)
223+
fmt.Fprintf(&sb, "%d", n)
225224
}
226-
buf.WriteByte(')')
225+
sb.WriteByte(')')
227226
i += len(match[0])
228227
break
229228
}
230-
buf.WriteString(regexp.QuoteMeta(string(c)))
229+
sb.WriteString(regexp.QuoteMeta(string(c)))
231230
case ',':
232231
if len(closingBraces) == 0 {
233-
buf.WriteString(regexp.QuoteMeta(string(c)))
232+
sb.WriteString(regexp.QuoteMeta(string(c)))
234233
} else {
235-
buf.WriteByte('|')
234+
sb.WriteByte('|')
236235
}
237236
case '}':
238237
if len(closingBraces) > 0 && closingBraces[len(closingBraces)-1] == i {
239-
buf.WriteByte(')')
238+
sb.WriteByte(')')
240239
closingBraces = closingBraces[:len(closingBraces)-1]
241240
} else {
242-
buf.WriteString(regexp.QuoteMeta(string(c)))
241+
sb.WriteString(regexp.QuoteMeta(string(c)))
243242
}
244243
default:
245244
if c > 128 {
246-
buf.WriteByte(c)
245+
sb.WriteByte(c)
247246
} else {
248-
buf.WriteString(regexp.QuoteMeta(string(c)))
247+
sb.WriteString(regexp.QuoteMeta(string(c)))
249248
}
250249
}
251250
}
252251
if mode&EntireString != 0 {
253-
buf.WriteString("$")
252+
sb.WriteString("$")
254253
}
255254
// No `.` metacharacters were used, so don't return the (?s) flag.
256255
if !dotMeta {
257-
return string(buf.Bytes()[4:]), nil
256+
return sb.String()[4:], nil
258257
}
259-
return buf.String(), nil
258+
return sb.String(), nil
260259
}
261260

262261
func charClass(s string) (string, error) {

0 commit comments

Comments
 (0)