Commit 04faa08c authored by Rob Pike's avatar Rob Pike

fmt: speed up floating point print, clean up some code

%g down to two mallocs from four. Also a mild speedup.

fmt_test.BenchmarkSprintfFloat         3016         2703  -10.38%

Fixes #2557.

R=rsc
CC=golang-dev
https://golang.org/cl/5491054
parent 29264c6f
......@@ -154,12 +154,17 @@ func putint(buf []byte, base, val uint64, digits string) int {
return i - 1
}
var (
trueBytes = []byte("true")
falseBytes = []byte("false")
)
// fmt_boolean formats a boolean.
func (f *fmt) fmt_boolean(v bool) {
if v {
f.padString("true")
f.pad(trueBytes)
} else {
f.padString("false")
f.pad(falseBytes)
}
}
......@@ -283,31 +288,18 @@ func (f *fmt) fmt_s(s string) {
}
// fmt_sx formats a string as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_sx(s string) {
t := ""
func (f *fmt) fmt_sx(s, digits string) {
// TODO: Avoid buffer by pre-padding.
var b bytes.Buffer
for i := 0; i < len(s); i++ {
if i > 0 && f.space {
t += " "
b.WriteByte(' ')
}
v := s[i]
t += string(ldigits[v>>4])
t += string(ldigits[v&0xF])
b.WriteByte(digits[v>>4])
b.WriteByte(digits[v&0xF])
}
f.padString(t)
}
// fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes.
func (f *fmt) fmt_sX(s string) {
t := ""
for i := 0; i < len(s); i++ {
if i > 0 && f.space {
t += " "
}
v := s[i]
t += string(udigits[v>>4])
t += string(udigits[v&0xF])
}
f.padString(t)
f.pad(b.Bytes())
}
// fmt_q formats a string as a double-quoted, escaped Go string constant.
......@@ -329,13 +321,13 @@ func (f *fmt) fmt_q(s string) {
// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
// If the character is not valid Unicode, it will print '\ufffd'.
func (f *fmt) fmt_qc(c int64) {
var quoted string
var quoted []byte
if f.plus {
quoted = strconv.QuoteRuneToASCII(rune(c))
quoted = strconv.AppendQuoteRuneToASCII(f.intbuf[0:0], rune(c))
} else {
quoted = strconv.QuoteRune(rune(c))
quoted = strconv.AppendQuoteRune(f.intbuf[0:0], rune(c))
}
f.padString(quoted)
f.pad(quoted)
}
// floating-point
......@@ -347,57 +339,70 @@ func doPrec(f *fmt, def int) int {
return def
}
// Add a plus sign or space to the floating-point string representation if missing and required.
func (f *fmt) plusSpace(s string) {
if s[0] != '-' {
// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...).
func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
// We leave one byte at the beginning of f.intbuf for a sign if needed,
// and make it a space, which we might be able to use.
f.intbuf[0] = ' '
slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
// Add a plus sign or space to the floating-point string representation if missing and required.
// The formatted number starts at slice[1].
switch slice[1] {
case '-', '+':
// We're set; drop the leading space.
slice = slice[1:]
default:
// There's no sign, but we might need one.
if f.plus {
s = "+" + s
slice[0] = '+'
} else if f.space {
s = " " + s
// space is already there
} else {
slice = slice[1:]
}
}
f.padString(s)
f.pad(slice)
}
// fmt_e64 formats a float64 in the form -1.23e+12.
func (f *fmt) fmt_e64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'e', doPrec(f, 6), 64)) }
func (f *fmt) fmt_e64(v float64) { f.formatFloat(v, 'e', doPrec(f, 6), 64) }
// fmt_E64 formats a float64 in the form -1.23E+12.
func (f *fmt) fmt_E64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'E', doPrec(f, 6), 64)) }
func (f *fmt) fmt_E64(v float64) { f.formatFloat(v, 'E', doPrec(f, 6), 64) }
// fmt_f64 formats a float64 in the form -1.23.
func (f *fmt) fmt_f64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'f', doPrec(f, 6), 64)) }
func (f *fmt) fmt_f64(v float64) { f.formatFloat(v, 'f', doPrec(f, 6), 64) }
// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
func (f *fmt) fmt_g64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'g', doPrec(f, -1), 64)) }
func (f *fmt) fmt_g64(v float64) { f.formatFloat(v, 'g', doPrec(f, -1), 64) }
// fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
func (f *fmt) fmt_G64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'G', doPrec(f, -1), 64)) }
func (f *fmt) fmt_G64(v float64) { f.formatFloat(v, 'G', doPrec(f, -1), 64) }
// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
func (f *fmt) fmt_fb64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'b', 0, 64)) }
func (f *fmt) fmt_fb64(v float64) { f.formatFloat(v, 'b', 0, 64) }
// float32
// cannot defer to float64 versions
// because it will get rounding wrong in corner cases.
// fmt_e32 formats a float32 in the form -1.23e+12.
func (f *fmt) fmt_e32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'e', doPrec(f, 6), 32)) }
func (f *fmt) fmt_e32(v float32) { f.formatFloat(float64(v), 'e', doPrec(f, 6), 32) }
// fmt_E32 formats a float32 in the form -1.23E+12.
func (f *fmt) fmt_E32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'E', doPrec(f, 6), 32)) }
func (f *fmt) fmt_E32(v float32) { f.formatFloat(float64(v), 'E', doPrec(f, 6), 32) }
// fmt_f32 formats a float32 in the form -1.23.
func (f *fmt) fmt_f32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'f', doPrec(f, 6), 32)) }
func (f *fmt) fmt_f32(v float32) { f.formatFloat(float64(v), 'f', doPrec(f, 6), 32) }
// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
func (f *fmt) fmt_g32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'g', doPrec(f, -1), 32)) }
func (f *fmt) fmt_g32(v float32) { f.formatFloat(float64(v), 'g', doPrec(f, -1), 32) }
// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'G', doPrec(f, -1), 32)) }
func (f *fmt) fmt_G32(v float32) { f.formatFloat(float64(v), 'G', doPrec(f, -1), 32) }
// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.FormatFloat(float64(v), 'b', 0, 32)) }
func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
// fmt_c64 formats a complex64 according to the verb.
func (f *fmt) fmt_c64(v complex64, verb rune) {
......
......@@ -503,9 +503,9 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
case 's':
p.fmt.fmt_s(v)
case 'x':
p.fmt.fmt_sx(v)
p.fmt.fmt_sx(v, ldigits)
case 'X':
p.fmt.fmt_sX(v)
p.fmt.fmt_sx(v, udigits)
case 'q':
p.fmt.fmt_q(v)
default:
......@@ -542,9 +542,9 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) {
case 's':
p.fmt.fmt_s(s)
case 'x':
p.fmt.fmt_sx(s)
p.fmt.fmt_sx(s, ldigits)
case 'X':
p.fmt.fmt_sX(s)
p.fmt.fmt_sx(s, udigits)
case 'q':
p.fmt.fmt_q(s)
default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment