experiment: render headers directly to output buffer to avoid a copy; minor speed boost
Russ Ross russ@russross.com
Sat, 25 Jun 2011 08:20:08 -0600
4 files changed,
34 insertions(+),
15 deletions(-)
M
block.go
→
block.go
@@ -186,10 +186,12 @@ for end > 0 && (data[end-1] == ' ' || data[end-1] == '\t') {
end-- } if end > i { - var work bytes.Buffer - parseInline(&work, rndr, data[i:end]) if rndr.mk.Header != nil { - rndr.mk.Header(out, work.Bytes(), level, rndr.mk.Opaque) + work := func() bool { + parseInline(out, rndr, data[i:end]) + return true + } + rndr.mk.Header(out, work, level, rndr.mk.Opaque) } } return skip@@ -1071,9 +1073,14 @@ // render the paragraph
renderParagraph(out, rndr, data[:prev]) // render the header - var work bytes.Buffer - parseInline(&work, rndr, data[prev:i-1]) - rndr.mk.Header(out, work.Bytes(), level, rndr.mk.Opaque) + // this ugly, convoluted closure avoids forcing variables onto the heap + work := func(o *bytes.Buffer, r *render, d []byte) func() bool { + return func() bool { + parseInline(o, r, d) + return true + } + }(out, rndr, data[prev:i-1]) + rndr.mk.Header(out, work, level, rndr.mk.Opaque) // find the end of the underline for ; i < len(data) && data[i] != '\n'; i++ {
M
html.go
→
html.go
@@ -163,10 +163,11 @@ out.Write(src[org:])
} } -func htmlHeader(out *bytes.Buffer, text []byte, level int, opaque interface{}) { +func htmlHeader(out *bytes.Buffer, text func() bool, level int, opaque interface{}) { options := opaque.(*htmlOptions) + marker := out.Len() - if out.Len() > 0 { + if marker > 0 { out.WriteByte('\n') }@@ -177,7 +178,10 @@ } else {
out.WriteString(fmt.Sprintf("<h%d>", level)) } - out.Write(text) + if !text() { + out.Truncate(marker) + return + } out.WriteString(fmt.Sprintf("</h%d>\n", level)) }@@ -572,8 +576,10 @@ func htmlNormalText(out *bytes.Buffer, text []byte, opaque interface{}) {
attrEscape(out, text) } -func htmlTocHeader(out *bytes.Buffer, text []byte, level int, opaque interface{}) { +func htmlTocHeader(out *bytes.Buffer, text func() bool, level int, opaque interface{}) { options := opaque.(*htmlOptions) + marker := out.Len() + for level > options.tocData.currentLevel { if options.tocData.currentLevel > 0 { out.WriteString("<li>")@@ -595,8 +601,9 @@ out.WriteString(strconv.Itoa(options.tocData.headerCount))
out.WriteString("\">") options.tocData.headerCount++ - if len(text) > 0 { - out.Write(text) + if !text() { + out.Truncate(marker) + return } out.WriteString("</a></li>\n") }
M
latex.go
→
latex.go
@@ -76,7 +76,9 @@ }
//BlockHtml func(out *bytes.Buffer, text []byte, opaque interface{}) -func latexHeader(out *bytes.Buffer, text []byte, level int, opaque interface{}) { +func latexHeader(out *bytes.Buffer, text func() bool, level int, opaque interface{}) { + marker := out.Len() + switch level { case 1: out.WriteString("\n\\section{")@@ -91,7 +93,10 @@ out.WriteString("\n\\subparagraph{")
case 6: out.WriteString("\n\\textbf{") } - out.Write(text) + if !text() { + out.Truncate(marker) + return + } out.WriteString("}\n") }
M
markdown.go
→
markdown.go
@@ -99,7 +99,7 @@ // block-level callbacks---nil skips the block
BlockCode func(out *bytes.Buffer, text []byte, lang string, opaque interface{}) BlockQuote func(out *bytes.Buffer, text []byte, opaque interface{}) BlockHtml func(out *bytes.Buffer, text []byte, opaque interface{}) - Header func(out *bytes.Buffer, text []byte, level int, opaque interface{}) + Header func(out *bytes.Buffer, text func() bool, level int, opaque interface{}) HRule func(out *bytes.Buffer, opaque interface{}) List func(out *bytes.Buffer, text []byte, flags int, opaque interface{}) ListItem func(out *bytes.Buffer, text []byte, flags int, opaque interface{})