mirror of
https://github.com/golang/go
synced 2024-11-25 07:17:56 -07: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:
parent
0b396a1731
commit
8218251498
@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
const debug = false // enable for debugging
|
||||
|
||||
const infinity = 1 << 30
|
||||
|
||||
type whiteSpace int
|
||||
|
||||
@ -33,18 +33,6 @@ const (
|
||||
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.
|
||||
var ignoreMultiLine = new(bool)
|
||||
|
||||
@ -58,7 +46,7 @@ const (
|
||||
|
||||
// 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)
|
||||
type osError struct {
|
||||
type printerError struct {
|
||||
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 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 {
|
||||
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
|
||||
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.
|
||||
// It updates p.pos as a side-effect.
|
||||
//
|
||||
func (p *printer) write(data []byte) {
|
||||
func (p *printer) write(data string) {
|
||||
i0 := 0
|
||||
for i, b := range data {
|
||||
switch b {
|
||||
for i := 0; i < len(data); i++ {
|
||||
switch data[i] {
|
||||
case '\n', '\f':
|
||||
// write segment ending in b
|
||||
// write segment ending in data[i]
|
||||
p.write0(data[i0 : i+1])
|
||||
|
||||
// update p.pos
|
||||
@ -172,6 +163,7 @@ func (p *printer) write(data []byte) {
|
||||
|
||||
if p.mode&inLiteral == 0 {
|
||||
// write indentation
|
||||
const htabs = "\t\t\t\t\t\t\t\t"
|
||||
// use "hard" htabs - indentation columns
|
||||
// must not be discarded by the tabwriter
|
||||
j := p.indent
|
||||
@ -211,9 +203,9 @@ func (p *printer) writeNewlines(n int, useFF bool) {
|
||||
if n > 0 {
|
||||
n = p.nlines(n, 0)
|
||||
if useFF {
|
||||
p.write(formfeeds[0:n])
|
||||
p.write("\f\f\f\f"[0:n])
|
||||
} 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 {
|
||||
// do not update p.pos - use write0
|
||||
_, 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
|
||||
}
|
||||
|
||||
@ -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
|
||||
// (which must be a /*-style comment): separate
|
||||
// with a blank instead of a tab
|
||||
p.write([]byte{' '})
|
||||
p.write(" ")
|
||||
} else {
|
||||
p.write(htab)
|
||||
p.write("\t")
|
||||
}
|
||||
}
|
||||
|
||||
@ -573,11 +565,10 @@ func (p *printer) writeComment(comment *ast.Comment) {
|
||||
|
||||
// write comment lines, separated by formfeed,
|
||||
// without a line break after the last line
|
||||
linebreak := formfeeds[0:1]
|
||||
pos := p.fset.Position(comment.Pos())
|
||||
for i, line := range lines {
|
||||
if i > 0 {
|
||||
p.write(linebreak)
|
||||
p.write("\f")
|
||||
pos = p.pos
|
||||
}
|
||||
if len(line) > 0 {
|
||||
@ -617,7 +608,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
|
||||
|
||||
// make sure we have a line break
|
||||
if needsLinebreak {
|
||||
p.write([]byte{'\n'})
|
||||
p.write("\n")
|
||||
}
|
||||
|
||||
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 {
|
||||
// the last comment is a /*-style comment and the next item
|
||||
// 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,
|
||||
// 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.
|
||||
func (p *printer) writeWhitespace(n int) {
|
||||
// write entries
|
||||
var data [1]byte
|
||||
for i := 0; i < n; i++ {
|
||||
switch ch := p.wsbuf[i]; ch {
|
||||
case ignore:
|
||||
@ -695,8 +685,7 @@ func (p *printer) writeWhitespace(n int) {
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
data[0] = byte(ch)
|
||||
p.write(data[0:])
|
||||
p.write(string(ch))
|
||||
}
|
||||
}
|
||||
|
||||
@ -871,6 +860,8 @@ const (
|
||||
// However, this would mess up any formatting done by
|
||||
// the tabwriter.
|
||||
|
||||
var aNewline = []byte("\n")
|
||||
|
||||
func (p *trimmer) Write(data []byte) (n int, err error) {
|
||||
// invariants:
|
||||
// p.state == inSpace:
|
||||
@ -889,8 +880,8 @@ func (p *trimmer) Write(data []byte) (n int, err error) {
|
||||
case '\t', ' ':
|
||||
p.space.WriteByte(b) // WriteByte returns no errors
|
||||
case '\n', '\f':
|
||||
p.space.Reset() // discard trailing space
|
||||
_, err = p.output.Write(newlines[0:1]) // write newline
|
||||
p.space.Reset() // discard trailing space
|
||||
_, err = p.output.Write(aNewline)
|
||||
case tabwriter.Escape:
|
||||
_, err = p.output.Write(p.space.Bytes())
|
||||
p.state = inEscape
|
||||
@ -917,7 +908,7 @@ func (p *trimmer) Write(data []byte) (n int, err error) {
|
||||
_, err = p.output.Write(data[m:n])
|
||||
p.state = inSpace
|
||||
p.space.Reset()
|
||||
_, err = p.output.Write(newlines[0:1]) // write newline
|
||||
_, err = p.output.Write(aNewline)
|
||||
case tabwriter.Escape:
|
||||
_, err = p.output.Write(data[m:n])
|
||||
p.state = inEscape
|
||||
@ -992,7 +983,7 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
|
||||
defer func() {
|
||||
written = p.written
|
||||
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.file(n)
|
||||
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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user