mirror of
https://github.com/golang/go
synced 2024-11-24 23:47:55 -07:00
go/printer: remove gratuitous string/[]byte conversions
Cleanup and slight performance improvement (1.5%). Before (best of 3 runs): printer.BenchmarkPrint 50 47377420 ns/op After (best of 3 runs): printer.BenchmarkPrint 50 46707180 ns/op R=rsc CC=golang-dev https://golang.org/cl/5416049
This commit is contained in:
parent
dd731478b8
commit
17e493a2b1
@ -362,25 +362,24 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(gri): It should be possible to convert the code below from using
|
|
||||||
// []byte to string and in the process eliminate some conversions.
|
|
||||||
|
|
||||||
// Split comment text into lines
|
// Split comment text into lines
|
||||||
func split(text []byte) [][]byte {
|
// (using strings.Split(text, "\n") is significantly slower for
|
||||||
|
// this specific purpose, as measured with: gotest -bench=Print)
|
||||||
|
func split(text string) []string {
|
||||||
// count lines (comment text never ends in a newline)
|
// count lines (comment text never ends in a newline)
|
||||||
n := 1
|
n := 1
|
||||||
for _, c := range text {
|
for i := 0; i < len(text); i++ {
|
||||||
if c == '\n' {
|
if text[i] == '\n' {
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// split
|
// split
|
||||||
lines := make([][]byte, n)
|
lines := make([]string, n)
|
||||||
n = 0
|
n = 0
|
||||||
i := 0
|
i := 0
|
||||||
for j, c := range text {
|
for j := 0; j < len(text); j++ {
|
||||||
if c == '\n' {
|
if text[j] == '\n' {
|
||||||
lines[n] = text[i:j] // exclude newline
|
lines[n] = text[i:j] // exclude newline
|
||||||
i = j + 1 // discard newline
|
i = j + 1 // discard newline
|
||||||
n++
|
n++
|
||||||
@ -391,16 +390,18 @@ func split(text []byte) [][]byte {
|
|||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
func isBlank(s []byte) bool {
|
// Returns true if s contains only white space
|
||||||
for _, b := range s {
|
// (only tabs and blanks can appear in the printer's context).
|
||||||
if b > ' ' {
|
func isBlank(s string) bool {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] > ' ' {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func commonPrefix(a, b []byte) []byte {
|
func commonPrefix(a, b string) string {
|
||||||
i := 0
|
i := 0
|
||||||
for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') {
|
for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') {
|
||||||
i++
|
i++
|
||||||
@ -408,7 +409,7 @@ func commonPrefix(a, b []byte) []byte {
|
|||||||
return a[0:i]
|
return a[0:i]
|
||||||
}
|
}
|
||||||
|
|
||||||
func stripCommonPrefix(lines [][]byte) {
|
func stripCommonPrefix(lines []string) {
|
||||||
if len(lines) < 2 {
|
if len(lines) < 2 {
|
||||||
return // at most one line - nothing to do
|
return // at most one line - nothing to do
|
||||||
}
|
}
|
||||||
@ -432,19 +433,21 @@ func stripCommonPrefix(lines [][]byte) {
|
|||||||
// Note that the first and last line are never empty (they
|
// Note that the first and last line are never empty (they
|
||||||
// contain the opening /* and closing */ respectively) and
|
// contain the opening /* and closing */ respectively) and
|
||||||
// thus they can be ignored by the blank line check.
|
// thus they can be ignored by the blank line check.
|
||||||
var prefix []byte
|
var prefix string
|
||||||
if len(lines) > 2 {
|
if len(lines) > 2 {
|
||||||
|
first := true
|
||||||
for i, line := range lines[1 : len(lines)-1] {
|
for i, line := range lines[1 : len(lines)-1] {
|
||||||
switch {
|
switch {
|
||||||
case isBlank(line):
|
case isBlank(line):
|
||||||
lines[1+i] = nil // range starts at line 1
|
lines[1+i] = "" // range starts at line 1
|
||||||
case prefix == nil:
|
case first:
|
||||||
prefix = commonPrefix(line, line)
|
prefix = commonPrefix(line, line)
|
||||||
|
first = false
|
||||||
default:
|
default:
|
||||||
prefix = commonPrefix(prefix, line)
|
prefix = commonPrefix(prefix, line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // len(lines) == 2
|
} else { // len(lines) == 2, lines cannot be blank (contain /* and */)
|
||||||
line := lines[1]
|
line := lines[1]
|
||||||
prefix = commonPrefix(line, line)
|
prefix = commonPrefix(line, line)
|
||||||
}
|
}
|
||||||
@ -453,7 +456,7 @@ func stripCommonPrefix(lines [][]byte) {
|
|||||||
* Check for vertical "line of stars" and correct prefix accordingly.
|
* Check for vertical "line of stars" and correct prefix accordingly.
|
||||||
*/
|
*/
|
||||||
lineOfStars := false
|
lineOfStars := false
|
||||||
if i := bytes.Index(prefix, []byte{'*'}); i >= 0 {
|
if i := strings.Index(prefix, "*"); i >= 0 {
|
||||||
// Line of stars present.
|
// Line of stars present.
|
||||||
if i > 0 && prefix[i-1] == ' ' {
|
if i > 0 && prefix[i-1] == ' ' {
|
||||||
i-- // remove trailing blank from prefix so stars remain aligned
|
i-- // remove trailing blank from prefix so stars remain aligned
|
||||||
@ -501,7 +504,7 @@ func stripCommonPrefix(lines [][]byte) {
|
|||||||
}
|
}
|
||||||
// Shorten the computed common prefix by the length of
|
// Shorten the computed common prefix by the length of
|
||||||
// suffix, if it is found as suffix of the prefix.
|
// suffix, if it is found as suffix of the prefix.
|
||||||
if bytes.HasSuffix(prefix, suffix) {
|
if strings.HasSuffix(prefix, string(suffix)) {
|
||||||
prefix = prefix[0 : len(prefix)-len(suffix)]
|
prefix = prefix[0 : len(prefix)-len(suffix)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -511,19 +514,18 @@ func stripCommonPrefix(lines [][]byte) {
|
|||||||
// with the opening /*, otherwise align the text with the other
|
// with the opening /*, otherwise align the text with the other
|
||||||
// lines.
|
// lines.
|
||||||
last := lines[len(lines)-1]
|
last := lines[len(lines)-1]
|
||||||
closing := []byte("*/")
|
closing := "*/"
|
||||||
i := bytes.Index(last, closing)
|
i := strings.Index(last, closing) // i >= 0 (closing is always present)
|
||||||
if isBlank(last[0:i]) {
|
if isBlank(last[0:i]) {
|
||||||
// last line only contains closing */
|
// last line only contains closing */
|
||||||
var sep []byte
|
|
||||||
if lineOfStars {
|
if lineOfStars {
|
||||||
// insert an aligning blank
|
closing = " */" // add blank to align final star
|
||||||
sep = []byte{' '}
|
|
||||||
}
|
}
|
||||||
lines[len(lines)-1] = bytes.Join([][]byte{prefix, closing}, sep)
|
lines[len(lines)-1] = prefix + closing
|
||||||
} else {
|
} else {
|
||||||
// last line contains more comment text - assume
|
// last line contains more comment text - assume
|
||||||
// it is aligned like the other lines
|
// it is aligned like the other lines and include
|
||||||
|
// in prefix computation
|
||||||
prefix = commonPrefix(prefix, last)
|
prefix = commonPrefix(prefix, last)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,9 +551,9 @@ func (p *printer) writeComment(comment *ast.Comment) {
|
|||||||
// update our own idea of the file and line number
|
// update our own idea of the file and line number
|
||||||
// accordingly, after printing the directive.
|
// accordingly, after printing the directive.
|
||||||
file := pos[:i]
|
file := pos[:i]
|
||||||
line, _ := strconv.Atoi(string(pos[i+1:]))
|
line, _ := strconv.Atoi(pos[i+1:])
|
||||||
defer func() {
|
defer func() {
|
||||||
p.pos.Filename = string(file)
|
p.pos.Filename = file
|
||||||
p.pos.Line = line
|
p.pos.Line = line
|
||||||
p.pos.Column = 1
|
p.pos.Column = 1
|
||||||
}()
|
}()
|
||||||
@ -566,7 +568,7 @@ func (p *printer) writeComment(comment *ast.Comment) {
|
|||||||
|
|
||||||
// for /*-style comments, print line by line and let the
|
// for /*-style comments, print line by line and let the
|
||||||
// write function take care of the proper indentation
|
// write function take care of the proper indentation
|
||||||
lines := split([]byte(text))
|
lines := split(text)
|
||||||
stripCommonPrefix(lines)
|
stripCommonPrefix(lines)
|
||||||
|
|
||||||
// write comment lines, separated by formfeed,
|
// write comment lines, separated by formfeed,
|
||||||
@ -579,7 +581,7 @@ func (p *printer) writeComment(comment *ast.Comment) {
|
|||||||
pos = p.pos
|
pos = p.pos
|
||||||
}
|
}
|
||||||
if len(line) > 0 {
|
if len(line) > 0 {
|
||||||
p.writeItem(pos, p.escape(string(line)))
|
p.writeItem(pos, p.escape(line))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user