mirror of
https://github.com/golang/go
synced 2024-11-22 03:44:39 -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 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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user