From: Paul Borman Date: Tue, 12 Jul 2016 15:54:09 +0000 (-0700) Subject: text/template: improve lexer performance in finding left delimiters. X-Git-Tag: go1.8beta1~1352 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=07b8011393dc3d3a78b3cd0857a31da339985994;p=gostls13.git 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 Run-TryBot: Rob Pike --- 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)))