Commit abcad1e5 authored by Martin Möhrmann's avatar Martin Möhrmann Committed by Rob Pike

fmt: change padding functions to avoid package init

Move the decision if zero padding is allowed to doPrintf
where the other formatting decisions are made.

Removes some dead code for negative f.wid that was never used
due to f.wid always being positive and f.minus deciding if left
or right padding should be used.

New padding code writes directly into the buffer and is as fast
as the old version but avoids the cost of needing package init.

name              old time/op  new time/op  delta
SprintfPadding-2   246ns ± 5%   245ns ± 4%   ~     (p=0.345 n=50+47)

Change-Id: I7dfddbac8e328f4ef0cdee8fafc0d06c784b2711
Reviewed-on: https://go-review.googlesource.com/19957
Run-TryBot: Rob Pike <r@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarRob Pike <r@golang.org>
parent 8b96bc68
...@@ -674,6 +674,10 @@ var fmtTests = []struct { ...@@ -674,6 +674,10 @@ var fmtTests = []struct {
// Make sure we can handle very large widths. // Make sure we can handle very large widths.
{"%0100f", -1.0, zeroFill("-", 99, "1.000000")}, {"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
// Use spaces instead of zero if padding to the right.
{"%0-5s", "abc", "abc "},
{"%-05.1f", 1.0, "1.0 "},
// Complex fmt used to leave the plus flag set for future entries in the array // Complex fmt used to leave the plus flag set for future entries in the array
// causing +2+0i and +3+0i instead of 2+0i and 3+0i. // causing +2+0i and +3+0i instead of 2+0i and 3+0i.
{"%v", []complex64{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"}, {"%v", []complex64{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"},
...@@ -884,6 +888,14 @@ func TestReorder(t *testing.T) { ...@@ -884,6 +888,14 @@ func TestReorder(t *testing.T) {
} }
} }
func BenchmarkSprintfPadding(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Sprintf("%16f", 1.0)
}
})
}
func BenchmarkSprintfEmpty(b *testing.B) { func BenchmarkSprintfEmpty(b *testing.B) {
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
for pb.Next() { for pb.Next() {
......
...@@ -23,16 +23,6 @@ const ( ...@@ -23,16 +23,6 @@ const (
unsigned = false unsigned = false
) )
var padZeroBytes = make([]byte, nByte)
var padSpaceBytes = make([]byte, nByte)
func init() {
for i := 0; i < nByte; i++ {
padZeroBytes[i] = '0'
padSpaceBytes[i] = ' '
}
}
// flags placed in a separate struct for easy clearing. // flags placed in a separate struct for easy clearing.
type fmtFlags struct { type fmtFlags struct {
widPresent bool widPresent bool
...@@ -72,70 +62,65 @@ func (f *fmt) init(buf *buffer) { ...@@ -72,70 +62,65 @@ func (f *fmt) init(buf *buffer) {
f.clearflags() f.clearflags()
} }
// computePadding computes left and right padding widths (only one will be non-zero).
func (f *fmt) computePadding(width int) (padding []byte, leftWidth, rightWidth int) {
left := !f.minus
w := f.wid
if w < 0 {
left = false
w = -w
}
w -= width
if w > 0 {
if left && f.zero {
return padZeroBytes, w, 0
}
if left {
return padSpaceBytes, w, 0
} else {
// can't be zero padding on the right
return padSpaceBytes, 0, w
}
}
return
}
// writePadding generates n bytes of padding. // writePadding generates n bytes of padding.
func (f *fmt) writePadding(n int, padding []byte) { func (f *fmt) writePadding(n int) {
for n > 0 { if n <= 0 { // No padding bytes needed.
m := n return
if m > nByte {
m = nByte
}
f.buf.Write(padding[0:m])
n -= m
} }
buf := *f.buf
oldLen := len(buf)
newLen := oldLen + n
// Make enough room for padding.
if newLen > cap(buf) {
buf = make(buffer, cap(buf)*2+n)
copy(buf, *f.buf)
}
// Decide which byte the padding should be filled with.
padByte := byte(' ')
if f.zero {
padByte = byte('0')
}
// Fill padding with padByte.
padding := buf[oldLen:newLen]
for i := range padding {
padding[i] = padByte
}
*f.buf = buf[:newLen]
} }
// pad appends b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus). // pad appends b to f.buf, padded on left (!f.minus) or right (f.minus).
func (f *fmt) pad(b []byte) { func (f *fmt) pad(b []byte) {
if !f.widPresent || f.wid == 0 { if !f.widPresent || f.wid == 0 {
f.buf.Write(b) f.buf.Write(b)
return return
} }
padding, left, right := f.computePadding(utf8.RuneCount(b)) width := f.wid - utf8.RuneCount(b)
if left > 0 { if !f.minus {
f.writePadding(left, padding) // left padding
} f.writePadding(width)
f.buf.Write(b) f.buf.Write(b)
if right > 0 { } else {
f.writePadding(right, padding) // right padding
f.buf.Write(b)
f.writePadding(width)
} }
} }
// padString appends s to buf, padded on left (w > 0) or right (w < 0 or f.minus). // padString appends s to f.buf, padded on left (!f.minus) or right (f.minus).
func (f *fmt) padString(s string) { func (f *fmt) padString(s string) {
if !f.widPresent || f.wid == 0 { if !f.widPresent || f.wid == 0 {
f.buf.WriteString(s) f.buf.WriteString(s)
return return
} }
padding, left, right := f.computePadding(utf8.RuneCountInString(s)) width := f.wid - utf8.RuneCountInString(s)
if left > 0 { if !f.minus {
f.writePadding(left, padding) // left padding
} f.writePadding(width)
f.buf.WriteString(s) f.buf.WriteString(s)
if right > 0 { } else {
f.writePadding(right, padding) // right padding
f.buf.WriteString(s)
f.writePadding(width)
} }
} }
......
...@@ -1235,6 +1235,12 @@ func (p *pp) doPrintf(format string, a []interface{}) { ...@@ -1235,6 +1235,12 @@ func (p *pp) doPrintf(format string, a []interface{}) {
p.fmt.plusV = true p.fmt.plusV = true
} }
} }
// Use space padding instead of zero padding to the right.
if p.fmt.minus {
p.fmt.zero = false
}
p.printArg(arg, c, 0) p.printArg(arg, c, 0)
} }
......
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