mirror of
https://github.com/golang/go
synced 2024-11-24 13:50:13 -07:00
fmt: optimize byte slice and array formatting for %v and %d
Instead of calling printArg in fmtBytes to format each byte call the byte formatting functions directly since it is known each element is of type byte. Add more tests for byte slice and array formatting. name old time/op new time/op delta SprintfBytes-2 843ns ±16% 417ns ±11% -50.58% (p=0.000 n=20+20) Change-Id: I5b907dbf52091e3de9710b09d67649c76f4c17e9 Reviewed-on: https://go-review.googlesource.com/20176 Run-TryBot: Rob Pike <r@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
8c838192b8
commit
00da3a6ec3
@ -422,8 +422,57 @@ var fmtTests = []struct {
|
||||
{"%v", &slice, "&[1 2 3 4 5]"},
|
||||
{"%v", &islice, "&[1 hello 2.5 <nil>]"},
|
||||
{"%v", &bslice, "&[1 2 3 4 5]"},
|
||||
{"%v", []byte{1}, "[1]"},
|
||||
|
||||
// byte slices and arrays with %d and %v variants
|
||||
{"%d", [0]byte{}, "[]"},
|
||||
{"%d", [1]byte{123}, "[123]"},
|
||||
{"%012d", []byte{}, "[]"},
|
||||
{"%d", [3]byte{1, 11, 111}, "[1 11 111]"},
|
||||
{"%d", [3]uint8{1, 11, 111}, "[1 11 111]"},
|
||||
{"%06d", [3]byte{1, 11, 111}, "[000001 000011 000111]"},
|
||||
{"%-6d", [3]byte{1, 11, 111}, "[1 11 111 ]"},
|
||||
{"%-06d", [3]byte{1, 11, 111}, "[1 11 111 ]"}, // 0 has no effect when - is present.
|
||||
{"%v", []byte{}, "[]"},
|
||||
{"%012v", []byte{}, "[]"},
|
||||
{"%#v", []byte{}, "[]byte{}"},
|
||||
{"%#v", []uint8{}, "[]byte{}"},
|
||||
{"%#012v", []byte{}, "[]byte{}"},
|
||||
{"%v", []byte{123}, "[123]"},
|
||||
{"%v", []byte{1, 11, 111}, "[1 11 111]"},
|
||||
{"%6v", []byte{1, 11, 111}, "[ 1 11 111]"},
|
||||
{"%06v", []byte{1, 11, 111}, "[000001 000011 000111]"},
|
||||
{"%-6v", []byte{1, 11, 111}, "[1 11 111 ]"},
|
||||
{"%-06v", []byte{1, 11, 111}, "[1 11 111 ]"},
|
||||
{"%#v", []byte{1, 11, 111}, "[]byte{0x1, 0xb, 0x6f}"},
|
||||
{"%#6v", []byte{1, 11, 111}, "[]byte{ 0x1, 0xb, 0x6f}"},
|
||||
{"%#06v", []byte{1, 11, 111}, "[]byte{0x000001, 0x00000b, 0x00006f}"},
|
||||
{"%#-6v", []byte{1, 11, 111}, "[]byte{0x1 , 0xb , 0x6f }"},
|
||||
{"%#-06v", []byte{1, 11, 111}, "[]byte{0x1 , 0xb , 0x6f }"},
|
||||
{"%v", [0]byte{}, "[]"},
|
||||
{"%-12v", [0]byte{}, "[]"},
|
||||
{"%#v", [0]byte{}, "[0]uint8{}"},
|
||||
{"%#v", [0]uint8{}, "[0]uint8{}"},
|
||||
{"%#-12v", [0]byte{}, "[0]uint8{}"},
|
||||
{"%v", [1]byte{123}, "[123]"},
|
||||
{"%v", [3]byte{1, 11, 111}, "[1 11 111]"},
|
||||
{"%06v", [3]byte{1, 11, 111}, "[000001 000011 000111]"},
|
||||
{"%-6v", [3]byte{1, 11, 111}, "[1 11 111 ]"},
|
||||
{"%-06v", [3]byte{1, 11, 111}, "[1 11 111 ]"},
|
||||
{"%#v", [3]byte{1, 11, 111}, "[3]uint8{0x1, 0xb, 0x6f}"},
|
||||
{"%#6v", [3]byte{1, 11, 111}, "[3]uint8{ 0x1, 0xb, 0x6f}"},
|
||||
{"%#06v", [3]byte{1, 11, 111}, "[3]uint8{0x000001, 0x00000b, 0x00006f}"},
|
||||
{"%#-6v", [3]byte{1, 11, 111}, "[3]uint8{0x1 , 0xb , 0x6f }"},
|
||||
{"%#-06v", [3]byte{1, 11, 111}, "[3]uint8{0x1 , 0xb , 0x6f }"},
|
||||
// f.space should and f.plus should not have an effect with %v.
|
||||
{"% v", []byte{1, 11, 111}, "[ 1 11 111]"},
|
||||
{"%+v", [3]byte{1, 11, 111}, "[1 11 111]"},
|
||||
{"%# -6v", []byte{1, 11, 111}, "[]byte{ 0x1 , 0xb , 0x6f }"},
|
||||
{"%#+-6v", [3]byte{1, 11, 111}, "[3]uint8{0x1 , 0xb , 0x6f }"},
|
||||
// f.space and f.plus should have an effect with %d.
|
||||
{"% d", []byte{1, 11, 111}, "[ 1 11 111]"},
|
||||
{"%+d", [3]byte{1, 11, 111}, "[+1 +11 +111]"},
|
||||
{"%# -6d", []byte{1, 11, 111}, "[ 1 11 111 ]"},
|
||||
{"%#+-6d", [3]byte{1, 11, 111}, "[+1 +11 +111 ]"},
|
||||
|
||||
// complexes with %v
|
||||
{"%v", 1 + 2i, "(1+2i)"},
|
||||
@ -809,6 +858,14 @@ var fmtTests = []struct {
|
||||
|
||||
// invalid reflect.Value doesn't crash.
|
||||
{"%v", reflect.Value{}, "<invalid reflect.Value>"},
|
||||
|
||||
// Tests to check that not supported verbs generate an error string.
|
||||
{"%☠", nil, "%!☠(<nil>)"},
|
||||
{"%☠", interface{}(nil), "%!☠(<nil>)"},
|
||||
{"%☠", []byte{0}, "%!☠([]uint8=[0])"},
|
||||
{"%☠", []uint8{0}, "%!☠([]uint8=[0])"},
|
||||
{"%☠", [1]byte{0}, "%!☠([1]uint8=[0])"},
|
||||
{"%☠", [1]uint8{0}, "%!☠([1]uint8=[0])"},
|
||||
}
|
||||
|
||||
// zeroFill generates zero-filled strings of the specified width. The length
|
||||
@ -1041,6 +1098,15 @@ func BenchmarkSprintfHexBytes(b *testing.B) {
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkSprintfBytes(b *testing.B) {
|
||||
data := []byte("0123456789abcdef")
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
Sprintf("%v", data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkManyArgs(b *testing.B) {
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
var buf bytes.Buffer
|
||||
|
@ -26,7 +26,7 @@ const (
|
||||
badIndexString = "(BADINDEX)"
|
||||
panicString = "(PANIC="
|
||||
extraString = "%!(EXTRA "
|
||||
bytesString = "[]byte{"
|
||||
bytesString = "[]byte"
|
||||
badWidthString = "%!(BADWIDTH)"
|
||||
badPrecString = "%!(BADPREC)"
|
||||
noVerbString = "%!(NOVERB)"
|
||||
@ -522,45 +522,33 @@ func (p *pp) fmtString(v string, verb rune) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) {
|
||||
if verb == 'v' || verb == 'd' {
|
||||
func (p *pp) fmtBytes(v []byte, verb rune, typeString string) {
|
||||
switch verb {
|
||||
case 'v', 'd':
|
||||
if p.fmt.sharpV {
|
||||
p.buf.WriteString(typeString)
|
||||
if v == nil {
|
||||
if typ == nil {
|
||||
p.buf.WriteString("[]byte(nil)")
|
||||
} else {
|
||||
p.buf.WriteString(typ.String())
|
||||
p.buf.WriteString(nilParenString)
|
||||
}
|
||||
return
|
||||
}
|
||||
if typ == nil {
|
||||
p.buf.WriteString(bytesString)
|
||||
} else {
|
||||
p.buf.WriteString(typ.String())
|
||||
p.buf.WriteByte('{')
|
||||
}
|
||||
} else {
|
||||
p.buf.WriteByte('[')
|
||||
}
|
||||
for i, c := range v {
|
||||
if i > 0 {
|
||||
if p.fmt.sharpV {
|
||||
p.buf.WriteString(commaSpaceString)
|
||||
} else {
|
||||
p.buf.WriteByte(' ')
|
||||
}
|
||||
p.fmt0x64(uint64(c), true)
|
||||
}
|
||||
p.printArg(c, 'v', depth+1)
|
||||
}
|
||||
if p.fmt.sharpV {
|
||||
p.buf.WriteByte('}')
|
||||
} else {
|
||||
p.buf.WriteByte('[')
|
||||
for i, c := range v {
|
||||
if i > 0 {
|
||||
p.buf.WriteByte(' ')
|
||||
}
|
||||
p.fmt.integer(int64(c), 10, unsigned, ldigits)
|
||||
}
|
||||
p.buf.WriteByte(']')
|
||||
}
|
||||
return
|
||||
}
|
||||
switch verb {
|
||||
case 's':
|
||||
p.fmt.fmt_s(string(v))
|
||||
case 'x':
|
||||
@ -788,7 +776,7 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) {
|
||||
case string:
|
||||
p.fmtString(f, verb)
|
||||
case []byte:
|
||||
p.fmtBytes(f, verb, nil, depth)
|
||||
p.fmtBytes(f, verb, bytesString)
|
||||
case reflect.Value:
|
||||
p.printReflectValue(f, verb, depth)
|
||||
return
|
||||
@ -957,13 +945,13 @@ BigSwitch:
|
||||
bytes[i] = byte(f.Index(i).Uint())
|
||||
}
|
||||
}
|
||||
p.fmtBytes(bytes, verb, typ, depth)
|
||||
p.fmtBytes(bytes, verb, typ.String())
|
||||
break
|
||||
}
|
||||
if p.fmt.sharpV {
|
||||
p.buf.WriteString(value.Type().String())
|
||||
if f.Kind() == reflect.Slice && f.IsNil() {
|
||||
p.buf.WriteString("(nil)")
|
||||
p.buf.WriteString(nilParenString)
|
||||
break
|
||||
}
|
||||
p.buf.WriteByte('{')
|
||||
|
Loading…
Reference in New Issue
Block a user