1
0
mirror of https://github.com/golang/go synced 2024-10-03 00:21:22 -06:00

go/printer: cleanup more string/byte conversions

Slight slow-down for printer benchmark (-0.7%) before
applying CL 5416049 (which will wash it out). Code is
cleaner and simpler.

R=rsc
CC=golang-dev
https://golang.org/cl/5417053
This commit is contained in:
Robert Griesemer 2011-11-18 20:55:35 -08:00
parent 0b396a1731
commit 8218251498

View File

@ -19,7 +19,7 @@ import (
) )
const debug = false // enable for debugging const debug = false // enable for debugging
const infinity = 1 << 30
type whiteSpace int type whiteSpace int
@ -33,18 +33,6 @@ const (
unindent = whiteSpace('<') unindent = whiteSpace('<')
) )
var (
esc = []byte{tabwriter.Escape}
htab = []byte{'\t'}
htabs = []byte("\t\t\t\t\t\t\t\t")
newlines = []byte("\n\n\n\n\n\n\n\n") // more than the max determined by nlines
formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines
)
// Special positions
var noPos token.Position // use noPos when a position is needed but not known
var infinity = 1 << 30
// Use ignoreMultiLine if the multiLine information is not important. // Use ignoreMultiLine if the multiLine information is not important.
var ignoreMultiLine = new(bool) var ignoreMultiLine = new(bool)
@ -58,7 +46,7 @@ const (
// local error wrapper so we can distinguish errors we want to return // local error wrapper so we can distinguish errors we want to return
// as errors from genuine panics (which we don't want to return as errors) // as errors from genuine panics (which we don't want to return as errors)
type osError struct { type printerError struct {
err error err error
} }
@ -143,12 +131,15 @@ func (p *printer) nlines(n, min int) int {
// write0 writes raw (uninterpreted) data to p.output and handles errors. // write0 writes raw (uninterpreted) data to p.output and handles errors.
// write0 does not indent after newlines, and does not HTML-escape or update p.pos. // write0 does not indent after newlines, and does not HTML-escape or update p.pos.
// //
func (p *printer) write0(data []byte) { func (p *printer) write0(data string) {
if len(data) > 0 { if len(data) > 0 {
n, err := p.output.Write(data) // TODO(gri) Replace bottleneck []byte conversion
// with writing into a bytes.Buffer.
// Will also simplify post-processing.
n, err := p.output.Write([]byte(data))
p.written += n p.written += n
if err != nil { if err != nil {
panic(osError{err}) panic(printerError{err})
} }
} }
} }
@ -157,12 +148,12 @@ func (p *printer) write0(data []byte) {
// after a line break unless in a tabwriter escape sequence. // after a line break unless in a tabwriter escape sequence.
// It updates p.pos as a side-effect. // It updates p.pos as a side-effect.
// //
func (p *printer) write(data []byte) { func (p *printer) write(data string) {
i0 := 0 i0 := 0
for i, b := range data { for i := 0; i < len(data); i++ {
switch b { switch data[i] {
case '\n', '\f': case '\n', '\f':
// write segment ending in b // write segment ending in data[i]
p.write0(data[i0 : i+1]) p.write0(data[i0 : i+1])
// update p.pos // update p.pos
@ -172,6 +163,7 @@ func (p *printer) write(data []byte) {
if p.mode&inLiteral == 0 { if p.mode&inLiteral == 0 {
// write indentation // write indentation
const htabs = "\t\t\t\t\t\t\t\t"
// use "hard" htabs - indentation columns // use "hard" htabs - indentation columns
// must not be discarded by the tabwriter // must not be discarded by the tabwriter
j := p.indent j := p.indent
@ -211,9 +203,9 @@ func (p *printer) writeNewlines(n int, useFF bool) {
if n > 0 { if n > 0 {
n = p.nlines(n, 0) n = p.nlines(n, 0)
if useFF { if useFF {
p.write(formfeeds[0:n]) p.write("\f\f\f\f"[0:n])
} else { } else {
p.write(newlines[0:n]) p.write("\n\n\n\n"[0:n])
} }
} }
} }
@ -240,9 +232,9 @@ func (p *printer) writeItem(pos token.Position, data string) {
if debug { if debug {
// do not update p.pos - use write0 // do not update p.pos - use write0
_, filename := filepath.Split(pos.Filename) _, filename := filepath.Split(pos.Filename)
p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, pos.Column))) p.write0(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, pos.Column))
} }
p.write([]byte(data)) p.write(data)
p.last = p.pos p.last = p.pos
} }
@ -301,9 +293,9 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
// next item is on the same line as the comment // next item is on the same line as the comment
// (which must be a /*-style comment): separate // (which must be a /*-style comment): separate
// with a blank instead of a tab // with a blank instead of a tab
p.write([]byte{' '}) p.write(" ")
} else { } else {
p.write(htab) p.write("\t")
} }
} }
@ -573,11 +565,10 @@ func (p *printer) writeComment(comment *ast.Comment) {
// write comment lines, separated by formfeed, // write comment lines, separated by formfeed,
// without a line break after the last line // without a line break after the last line
linebreak := formfeeds[0:1]
pos := p.fset.Position(comment.Pos()) pos := p.fset.Position(comment.Pos())
for i, line := range lines { for i, line := range lines {
if i > 0 { if i > 0 {
p.write(linebreak) p.write("\f")
pos = p.pos pos = p.pos
} }
if len(line) > 0 { if len(line) > 0 {
@ -617,7 +608,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
// make sure we have a line break // make sure we have a line break
if needsLinebreak { if needsLinebreak {
p.write([]byte{'\n'}) p.write("\n")
} }
return return
@ -643,7 +634,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
if last.Text[1] == '*' && p.fset.Position(last.Pos()).Line == next.Line { if last.Text[1] == '*' && p.fset.Position(last.Pos()).Line == next.Line {
// the last comment is a /*-style comment and the next item // the last comment is a /*-style comment and the next item
// follows on the same line: separate with an extra blank // follows on the same line: separate with an extra blank
p.write([]byte{' '}) p.write(" ")
} }
// ensure that there is a line break after a //-style comment, // ensure that there is a line break after a //-style comment,
// before a closing '}' unless explicitly disabled, or at eof // before a closing '}' unless explicitly disabled, or at eof
@ -663,7 +654,6 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
// whiteWhitespace writes the first n whitespace entries. // whiteWhitespace writes the first n whitespace entries.
func (p *printer) writeWhitespace(n int) { func (p *printer) writeWhitespace(n int) {
// write entries // write entries
var data [1]byte
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
switch ch := p.wsbuf[i]; ch { switch ch := p.wsbuf[i]; ch {
case ignore: case ignore:
@ -695,8 +685,7 @@ func (p *printer) writeWhitespace(n int) {
} }
fallthrough fallthrough
default: default:
data[0] = byte(ch) p.write(string(ch))
p.write(data[0:])
} }
} }
@ -871,6 +860,8 @@ const (
// However, this would mess up any formatting done by // However, this would mess up any formatting done by
// the tabwriter. // the tabwriter.
var aNewline = []byte("\n")
func (p *trimmer) Write(data []byte) (n int, err error) { func (p *trimmer) Write(data []byte) (n int, err error) {
// invariants: // invariants:
// p.state == inSpace: // p.state == inSpace:
@ -889,8 +880,8 @@ func (p *trimmer) Write(data []byte) (n int, err error) {
case '\t', ' ': case '\t', ' ':
p.space.WriteByte(b) // WriteByte returns no errors p.space.WriteByte(b) // WriteByte returns no errors
case '\n', '\f': case '\n', '\f':
p.space.Reset() // discard trailing space p.space.Reset() // discard trailing space
_, err = p.output.Write(newlines[0:1]) // write newline _, err = p.output.Write(aNewline)
case tabwriter.Escape: case tabwriter.Escape:
_, err = p.output.Write(p.space.Bytes()) _, err = p.output.Write(p.space.Bytes())
p.state = inEscape p.state = inEscape
@ -917,7 +908,7 @@ func (p *trimmer) Write(data []byte) (n int, err error) {
_, err = p.output.Write(data[m:n]) _, err = p.output.Write(data[m:n])
p.state = inSpace p.state = inSpace
p.space.Reset() p.space.Reset()
_, err = p.output.Write(newlines[0:1]) // write newline _, err = p.output.Write(aNewline)
case tabwriter.Escape: case tabwriter.Escape:
_, err = p.output.Write(data[m:n]) _, err = p.output.Write(data[m:n])
p.state = inEscape p.state = inEscape
@ -992,7 +983,7 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
defer func() { defer func() {
written = p.written written = p.written
if e := recover(); e != nil { if e := recover(); e != nil {
err = e.(osError).err // re-panics if it's not a local osError err = e.(printerError).err // re-panics if it's not a printerError
} }
}() }()
@ -1020,7 +1011,7 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
p.useNodeComments = n.Comments == nil p.useNodeComments = n.Comments == nil
p.file(n) p.file(n)
default: default:
panic(osError{fmt.Errorf("printer.Fprint: unsupported node type %T", n)}) panic(printerError{fmt.Errorf("printer.Fprint: unsupported node type %T", n)})
} }
p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF) p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF)