aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.go2
-rw-r--r--func.go14
-rw-r--r--func_test.go21
-rw-r--r--strutil.go34
-rw-r--r--strutil_test.go10
5 files changed, 57 insertions, 24 deletions
diff --git a/eval.go b/eval.go
index 173ec45..915b852 100644
--- a/eval.go
+++ b/eval.go
@@ -73,7 +73,7 @@ func newEvaluator(vars map[string]Var) *Evaluator {
}
func (ev *Evaluator) args(buf *buffer, args ...Value) [][]byte {
- var pos []int
+ pos := make([]int, 0, len(args))
for _, arg := range args {
arg.Eval(buf, ev)
pos = append(pos, buf.Len())
diff --git a/func.go b/func.go
index 62e9af4..f6c3b41 100644
--- a/func.go
+++ b/func.go
@@ -182,10 +182,18 @@ func (f *funcPatsubst) Eval(w io.Writer, ev *Evaluator) {
pat := fargs[0]
repl := fargs[1]
ws := newWordScanner(fargs[2])
- sw := ssvWriter{w: w}
+ space := false
for ws.Scan() {
- t := substPatternBytes(pat, repl, ws.Bytes())
- sw.Write(t)
+ if space {
+ writeByte(w, ' ')
+ }
+ pre, subst, post := substPatternBytes(pat, repl, ws.Bytes())
+ w.Write(pre)
+ if subst != nil {
+ w.Write(subst)
+ w.Write(post)
+ }
+ space = true
}
freeBuf(abuf)
addStats("funcbody", "patsubst", t)
diff --git a/func_test.go b/func_test.go
index 7fae5f2..6758a9b 100644
--- a/func_test.go
+++ b/func_test.go
@@ -56,3 +56,24 @@ func BenchmarkFuncSort(b *testing.B) {
sort.Eval(&buf, ev)
}
}
+
+func BenchmarkFuncPatsubst(b *testing.B) {
+ patsubst := &funcPatsubst{
+ fclosure: fclosure{
+ args: []Value{
+ literal("(patsubst"),
+ literal("%.java"),
+ literal("%.class"),
+ literal("foo.jar bar.java baz.h"),
+ },
+ },
+ }
+ ev := newEvaluator(make(map[string]Var))
+ var buf bytes.Buffer
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ patsubst.Eval(&buf, ev)
+ }
+}
diff --git a/strutil.go b/strutil.go
index 83305cb..689537f 100644
--- a/strutil.go
+++ b/strutil.go
@@ -154,40 +154,36 @@ func substPattern(pat, repl, str string) string {
return rs[0] + trimed + rs[1]
}
-func substPatternBytes(pat, repl, str []byte) []byte {
- ps := bytes.SplitN(pat, []byte{'%'}, 2)
- if len(ps) != 2 {
+func substPatternBytes(pat, repl, str []byte) (pre, subst, post []byte) {
+ i := bytes.IndexByte(pat, '%')
+ if i < 0 {
if bytes.Equal(str, pat) {
- return repl
+ return repl, nil, nil
}
- return str
+ return str, nil, nil
}
in := str
trimed := str
- if len(ps[0]) != 0 {
- trimed = bytes.TrimPrefix(in, ps[0])
+ if i > 0 {
+ trimed = bytes.TrimPrefix(in, pat[:i])
if bytes.Equal(trimed, in) {
- return str
+ return str, nil, nil
}
}
in = trimed
- if len(ps[1]) != 0 {
- trimed = bytes.TrimSuffix(in, ps[1])
+ if i < len(pat)-1 {
+ trimed = bytes.TrimSuffix(in, pat[i+1:])
if bytes.Equal(trimed, in) {
- return str
+ return str, nil, nil
}
}
- rs := bytes.SplitN(repl, []byte{'%'}, 2)
- if len(rs) != 2 {
- return repl
+ i = bytes.IndexByte(repl, '%')
+ if i < 0 {
+ return repl, nil, nil
}
- r := make([]byte, 0, len(rs[0])+len(trimed)+len(rs[1])+1)
- r = append(r, rs[0]...)
- r = append(r, trimed...)
- r = append(r, rs[1]...)
- return r
+ return repl[:i], trimed, repl[i+1:]
}
func substRef(pat, repl, str string) string {
diff --git a/strutil_test.go b/strutil_test.go
index 377780d..0cd77ed 100644
--- a/strutil_test.go
+++ b/strutil_test.go
@@ -91,6 +91,14 @@ func TestWordScanner(t *testing.T) {
}
func TestSubstPattern(t *testing.T) {
+ concatStr := func(pre, subst, post []byte) string {
+ var s []byte
+ s = append(s, pre...)
+ s = append(s, subst...)
+ s = append(s, post...)
+ return string(s)
+ }
+
for _, tc := range []struct {
pat string
repl string
@@ -151,7 +159,7 @@ func TestSubstPattern(t *testing.T) {
t.Errorf(`substPattern(%q,%q,%q)=%q, want %q`, tc.pat, tc.repl, tc.in, got, tc.want)
}
- got = string(substPatternBytes([]byte(tc.pat), []byte(tc.repl), []byte(tc.in)))
+ got = concatStr(substPatternBytes([]byte(tc.pat), []byte(tc.repl), []byte(tc.in)))
if got != tc.want {
fmt.Printf("substPatternBytes(%q,%q,%q)=%q, want %q\n", tc.pat, tc.repl, tc.in, got, tc.want)
t.Errorf(`substPatternBytes(%q,%q,%q)=%q, want %q`, tc.pat, tc.repl, tc.in, got, tc.want)