Commit 07b80113 authored by Paul Borman's avatar Paul Borman Committed by Rob Pike

text/template: improve lexer performance in finding left delimiters.

The existing implementation calls l.next for each run up to the next
instance of the left delimiter ({{).  For ascii text, this is multiple
function calls per byte.  Change to use strings.Index to find the left
delimiter.  The performace improvement ranges from 1:1 (no text outside
of {{}}'s) to multiple times faster (9:1 was seen on 8K of text with no
{{ }}'s).

Change-Id: I2f82bea63b78b6714f09a725f7b2bbb00a3448a3
Reviewed-on: https://go-review.googlesource.com/24863Reviewed-by: default avatarRob Pike <r@golang.org>
Run-TryBot: Rob Pike <r@golang.org>
parent 8f9671d1
...@@ -236,24 +236,23 @@ const ( ...@@ -236,24 +236,23 @@ const (
// lexText scans until an opening action delimiter, "{{". // lexText scans until an opening action delimiter, "{{".
func lexText(l *lexer) stateFn { func lexText(l *lexer) stateFn {
for { l.width = 0
delim, trimSpace := l.atLeftDelim() if x := strings.Index(l.input[l.pos:], l.leftDelim); x >= 0 {
if delim { ldn := Pos(len(l.leftDelim))
trimLength := Pos(0) l.pos += Pos(x)
if trimSpace { trimLength := Pos(0)
trimLength = rightTrimLength(l.input[l.start:l.pos]) if strings.HasPrefix(l.input[l.pos+ldn:], leftTrimMarker) {
} trimLength = rightTrimLength(l.input[l.start:l.pos])
l.pos -= trimLength
if l.pos > l.start {
l.emit(itemText)
}
l.pos += trimLength
l.ignore()
return lexLeftDelim
} }
if l.next() == eof { l.pos -= trimLength
break if l.pos > l.start {
l.emit(itemText)
} }
l.pos += trimLength
l.ignore()
return lexLeftDelim
} else {
l.pos = Pos(len(l.input))
} }
// Correctly reached EOF. // Correctly reached EOF.
if l.pos > l.start { if l.pos > l.start {
...@@ -263,16 +262,6 @@ func lexText(l *lexer) stateFn { ...@@ -263,16 +262,6 @@ func lexText(l *lexer) stateFn {
return nil return nil
} }
// atLeftDelim reports whether the lexer is at a left delimiter, possibly followed by a trim marker.
func (l *lexer) atLeftDelim() (delim, trimSpaces bool) {
if !strings.HasPrefix(l.input[l.pos:], l.leftDelim) {
return false, false
}
// The left delim might have the marker afterwards.
trimSpaces = strings.HasPrefix(l.input[l.pos+Pos(len(l.leftDelim)):], leftTrimMarker)
return true, trimSpaces
}
// rightTrimLength returns the length of the spaces at the end of the string. // rightTrimLength returns the length of the spaces at the end of the string.
func rightTrimLength(s string) Pos { func rightTrimLength(s string) Pos {
return Pos(len(s) - len(strings.TrimRight(s, spaceChars))) return Pos(len(s) - len(strings.TrimRight(s, spaceChars)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment