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--
}
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 @@ func blockParagraph(out *bytes.Buffer, rndr *render, data []byte) int {
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++ {

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)
marker := out.Len()
if out.Len() > 0 {
if marker > 0 {
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.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 @@ func htmlTocHeader(out *bytes.Buffer, text []byte, level int, opaque interface{}
out.WriteString("\">")
options.tocData.headerCount++
if len(text) > 0 {
out.Write(text)
if !text() {
out.Truncate(marker)
return
}
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{})
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 @@ func latexHeader(out *bytes.Buffer, text []byte, level int, opaque interface{})
case 6:
out.WriteString("\n\\textbf{")
}
out.Write(text)
if !text() {
out.Truncate(marker)
return
}
out.WriteString("}\n")
}

View File

@ -99,7 +99,7 @@ type Renderer struct {
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{})