aboutsummaryrefslogtreecommitdiff
path: root/src/text
diff options
context:
space:
mode:
authorPaul Borman <borman@google.com>2016-07-12 08:54:09 -0700
committerRob Pike <r@golang.org>2016-09-13 12:51:13 +0000
commit07b8011393dc3d3a78b3cd0857a31da339985994 (patch)
tree2099a7bcc49acd21bef70d46ba43fc7f5f070623 /src/text
parent8f9671d11a219d8fc9a6176ddf9939e743982ffc (diff)
downloadgo-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.go41
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)))