diff options
-rw-r--r-- | eval.go | 2 | ||||
-rw-r--r-- | func.go | 14 | ||||
-rw-r--r-- | func_test.go | 21 | ||||
-rw-r--r-- | strutil.go | 34 | ||||
-rw-r--r-- | strutil_test.go | 10 |
5 files changed, 57 insertions, 24 deletions
@@ -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()) @@ -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) + } +} @@ -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) |