mirror of
https://github.com/golang/go
synced 2024-11-20 05:34:40 -07:00
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
This commit is contained in:
parent
29264c6f4f
commit
04faa08c07
@ -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
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (f *fmt) plusSpace(s string) {
|
||||
if s[0] != '-' {
|
||||
// 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:
|
||||
|
Loading…
Reference in New Issue
Block a user