diff options
| author | Paul Borman <borman@google.com> | 2016-07-12 08:54:09 -0700 |
|---|---|---|
| committer | Rob Pike <r@golang.org> | 2016-09-13 12:51:13 +0000 |
| commit | 07b8011393dc3d3a78b3cd0857a31da339985994 (patch) | |
| tree | 2099a7bcc49acd21bef70d46ba43fc7f5f070623 /src/text | |
| parent | 8f9671d11a219d8fc9a6176ddf9939e743982ffc (diff) | |
| download | go-07b8011393dc3d3a78b3cd0857a31da339985994.tar.xz | |
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/24863
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Rob Pike <r@golang.org>
Diffstat (limited to 'src/text')
| -rw-r--r-- | src/text/template/parse/lex.go | 41 |
1 files changed, 15 insertions, 26 deletions
diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go index 079c0ea6f7..7811cc1d4f 100644 --- a/src/text/template/parse/lex.go +++ b/src/text/template/parse/lex.go @@ -236,24 +236,23 @@ const ( // lexText scans until an opening action delimiter, "{{". func lexText(l *lexer) stateFn { - for { - delim, trimSpace := l.atLeftDelim() - if delim { - trimLength := Pos(0) - if trimSpace { - 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 + l.width = 0 + if x := strings.Index(l.input[l.pos:], l.leftDelim); x >= 0 { + ldn := Pos(len(l.leftDelim)) + l.pos += Pos(x) + trimLength := Pos(0) + if strings.HasPrefix(l.input[l.pos+ldn:], leftTrimMarker) { + trimLength = rightTrimLength(l.input[l.start:l.pos]) } - if l.next() == eof { - break + l.pos -= trimLength + 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. if l.pos > l.start { @@ -263,16 +262,6 @@ func lexText(l *lexer) stateFn { 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. func rightTrimLength(s string) Pos { return Pos(len(s) - len(strings.TrimRight(s, spaceChars))) |
