experiment: render headers directly to output buffer to avoid a copy; minor speed boost

This commit is contained in:
Russ Ross 2011-06-25 08:20:08 -06:00
parent 45ab8d0dc4
commit cf97fbd897
4 changed files with 34 additions and 15 deletions

View File

@ -186,10 +186,12 @@ func blockPrefixHeader(out *bytes.Buffer, rndr *render, data []byte) int {
end-- end--
} }
if end > i { if end > i {
var work bytes.Buffer
parseInline(&work, rndr, data[i:end])
if rndr.mk.Header != nil { 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 return skip
@ -1071,9 +1073,14 @@ func blockParagraph(out *bytes.Buffer, rndr *render, data []byte) int {
renderParagraph(out, rndr, data[:prev]) renderParagraph(out, rndr, data[:prev])
// render the header // render the header
var work bytes.Buffer // this ugly, convoluted closure avoids forcing variables onto the heap
parseInline(&work, rndr, data[prev:i-1]) work := func(o *bytes.Buffer, r *render, d []byte) func() bool {
rndr.mk.Header(out, work.Bytes(), level, rndr.mk.Opaque) 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 // find the end of the underline
for ; i < len(data) && data[i] != '\n'; i++ { for ; i < len(data) && data[i] != '\n'; i++ {

19
html.go
View File

@ -163,10 +163,11 @@ func attrEscape(out *bytes.Buffer, src []byte) {
} }
} }
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) options := opaque.(*htmlOptions)
marker := out.Len()
if out.Len() > 0 { if marker > 0 {
out.WriteByte('\n') out.WriteByte('\n')
} }
@ -177,7 +178,10 @@ func htmlHeader(out *bytes.Buffer, text []byte, level int, opaque interface{}) {
out.WriteString(fmt.Sprintf("<h%d>", level)) out.WriteString(fmt.Sprintf("<h%d>", level))
} }
out.Write(text) if !text() {
out.Truncate(marker)
return
}
out.WriteString(fmt.Sprintf("</h%d>\n", level)) out.WriteString(fmt.Sprintf("</h%d>\n", level))
} }
@ -572,8 +576,10 @@ func htmlNormalText(out *bytes.Buffer, text []byte, opaque interface{}) {
attrEscape(out, text) 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) options := opaque.(*htmlOptions)
marker := out.Len()
for level > options.tocData.currentLevel { for level > options.tocData.currentLevel {
if options.tocData.currentLevel > 0 { if options.tocData.currentLevel > 0 {
out.WriteString("<li>") out.WriteString("<li>")
@ -595,8 +601,9 @@ func htmlTocHeader(out *bytes.Buffer, text []byte, level int, opaque interface{}
out.WriteString("\">") out.WriteString("\">")
options.tocData.headerCount++ options.tocData.headerCount++
if len(text) > 0 { if !text() {
out.Write(text) out.Truncate(marker)
return
} }
out.WriteString("</a></li>\n") out.WriteString("</a></li>\n")
} }

View File

@ -76,7 +76,9 @@ func latexBlockQuote(out *bytes.Buffer, text []byte, opaque interface{}) {
//BlockHtml func(out *bytes.Buffer, text []byte, opaque interface{}) //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 { switch level {
case 1: case 1:
out.WriteString("\n\\section{") out.WriteString("\n\\section{")
@ -91,7 +93,10 @@ func latexHeader(out *bytes.Buffer, text []byte, level int, opaque interface{})
case 6: case 6:
out.WriteString("\n\\textbf{") out.WriteString("\n\\textbf{")
} }
out.Write(text) if !text() {
out.Truncate(marker)
return
}
out.WriteString("}\n") out.WriteString("}\n")
} }

View File

@ -99,7 +99,7 @@ type Renderer struct {
BlockCode func(out *bytes.Buffer, text []byte, lang string, opaque interface{}) BlockCode func(out *bytes.Buffer, text []byte, lang string, opaque interface{})
BlockQuote func(out *bytes.Buffer, text []byte, opaque interface{}) BlockQuote func(out *bytes.Buffer, text []byte, opaque interface{})
BlockHtml 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{}) HRule func(out *bytes.Buffer, opaque interface{})
List func(out *bytes.Buffer, text []byte, flags int, opaque interface{}) List func(out *bytes.Buffer, text []byte, flags int, opaque interface{})
ListItem func(out *bytes.Buffer, text []byte, flags int, opaque interface{}) ListItem func(out *bytes.Buffer, text []byte, flags int, opaque interface{})