From cf97fbd89772bdcef0e088d38e9ce4ecb261ea15 Mon Sep 17 00:00:00 2001 From: Russ Ross Date: Sat, 25 Jun 2011 08:20:08 -0600 Subject: [PATCH] experiment: render headers directly to output buffer to avoid a copy; minor speed boost --- block.go | 19 +++++++++++++------ html.go | 19 +++++++++++++------ latex.go | 9 +++++++-- markdown.go | 2 +- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/block.go b/block.go index 9ced72e..abe627d 100644 --- a/block.go +++ b/block.go @@ -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++ { diff --git a/html.go b/html.go index 3ece7e5..2ec7997 100644 --- a/html.go +++ b/html.go @@ -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("", level)) } - out.Write(text) + if !text() { + out.Truncate(marker) + return + } out.WriteString(fmt.Sprintf("\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("
  • ") @@ -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("
  • \n") } diff --git a/latex.go b/latex.go index 00a98f0..3a617a4 100644 --- a/latex.go +++ b/latex.go @@ -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") } diff --git a/markdown.go b/markdown.go index 4fa2586..0d5c0bd 100644 --- a/markdown.go +++ b/markdown.go @@ -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{})