mirror of
https://github.com/golang/go
synced 2024-11-21 21:54:40 -07:00
strconv: 34% to 63% faster conversions
(Note that the Int and Uint benchmarks use different test sets and thus cannot be compared against each other. Int and Uint conversions are approximately the same speed). Before (best of 3 runs): strconv_test.BenchmarkFormatInt 100000 15636 ns/op strconv_test.BenchmarkAppendInt 100000 18930 ns/op strconv_test.BenchmarkFormatUint 500000 4392 ns/op strconv_test.BenchmarkAppendUint 500000 5152 ns/op After (best of 3 runs): strconv_test.BenchmarkFormatInt 200000 10070 ns/op (-36%) strconv_test.BenchmarkAppendInt 200000 7097 ns/op (-63%) strconv_test.BenchmarkFormatUint 1000000 2893 ns/op (-34%) strconv_test.BenchmarkAppendUint 500000 2462 ns/op (-52%) R=r, rsc, r CC=golang-dev https://golang.org/cl/5449093
This commit is contained in:
parent
46deaa297b
commit
e0c006a9b0
@ -6,37 +6,14 @@ package strconv
|
||||
|
||||
// FormatUint returns the string representation of i in the given base.
|
||||
func FormatUint(i uint64, base int) string {
|
||||
u := i
|
||||
if base < 2 || 36 < base {
|
||||
panic("invalid base " + Itoa(base))
|
||||
}
|
||||
if u == 0 {
|
||||
return "0"
|
||||
}
|
||||
|
||||
// Assemble decimal in reverse order.
|
||||
var buf [64]byte
|
||||
j := len(buf)
|
||||
b := uint64(base)
|
||||
for u > 0 {
|
||||
j--
|
||||
buf[j] = "0123456789abcdefghijklmnopqrstuvwxyz"[u%b]
|
||||
u /= b
|
||||
}
|
||||
|
||||
return string(buf[j:])
|
||||
_, s := formatBits(nil, i, base, false, false)
|
||||
return s
|
||||
}
|
||||
|
||||
// FormatInt returns the string representation of i in the given base.
|
||||
func FormatInt(i int64, base int) string {
|
||||
if i == 0 {
|
||||
return "0"
|
||||
}
|
||||
|
||||
if i < 0 {
|
||||
return "-" + FormatUint(-uint64(i), base)
|
||||
}
|
||||
return FormatUint(uint64(i), base)
|
||||
_, s := formatBits(nil, uint64(i), base, true, false)
|
||||
return s
|
||||
}
|
||||
|
||||
// Itoa is shorthand for FormatInt(i, 10).
|
||||
@ -47,11 +24,95 @@ func Itoa(i int) string {
|
||||
// AppendInt appends the string form of the integer i,
|
||||
// as generated by FormatInt, to dst and returns the extended buffer.
|
||||
func AppendInt(dst []byte, i int64, base int) []byte {
|
||||
return append(dst, FormatInt(i, base)...)
|
||||
dst, _ = formatBits(dst, uint64(i), base, true, true)
|
||||
return dst
|
||||
}
|
||||
|
||||
// AppendUint appends the string form of the unsigned integer i,
|
||||
// as generated by FormatUint, to dst and returns the extended buffer.
|
||||
func AppendUint(dst []byte, i uint64, base int) []byte {
|
||||
return append(dst, FormatUint(i, base)...)
|
||||
dst, _ = formatBits(dst, i, base, false, true)
|
||||
return dst
|
||||
}
|
||||
|
||||
const digits = "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
var shifts = [len(digits) + 1]uint{
|
||||
1 << 1: 1,
|
||||
1 << 2: 2,
|
||||
1 << 3: 3,
|
||||
1 << 4: 4,
|
||||
1 << 5: 5,
|
||||
}
|
||||
|
||||
// formatBits computes the string representation of u in the given base.
|
||||
// If signed is set, u is treated as int64 value. If append_ is set, the
|
||||
// string is appended to dst and the resulting byte slice is returned as
|
||||
// the first result value; otherwise the string is simply returned as the
|
||||
// second result value.
|
||||
//
|
||||
func formatBits(dst []byte, u uint64, base int, signed, append_ bool) (d []byte, s string) {
|
||||
if base < 2 || base > len(digits) {
|
||||
panic("invalid base")
|
||||
}
|
||||
// 2 <= base && base <= len(digits)
|
||||
|
||||
if u == 0 {
|
||||
if append_ {
|
||||
d = append(dst, '0')
|
||||
return
|
||||
}
|
||||
s = "0"
|
||||
return
|
||||
}
|
||||
|
||||
var a [64 + 1]byte // +1 for sign of 64bit value in base 2
|
||||
i := len(a)
|
||||
|
||||
x := int64(u)
|
||||
if x < 0 && signed {
|
||||
u = -u
|
||||
}
|
||||
|
||||
// convert bits
|
||||
if base == 10 {
|
||||
// common case: use constant 10 for / and % because
|
||||
// the compiler can optimize it into a multiply+shift
|
||||
for u != 0 {
|
||||
i--
|
||||
a[i] = digits[u%10]
|
||||
u /= 10
|
||||
}
|
||||
|
||||
} else if s := shifts[base]; s > 0 {
|
||||
// base is power of 2: use shifts and masks instead of / and %
|
||||
m := uintptr(1)<<s - 1
|
||||
for u != 0 {
|
||||
i--
|
||||
a[i] = digits[uintptr(u)&m]
|
||||
u >>= s
|
||||
}
|
||||
|
||||
} else {
|
||||
// general case
|
||||
b := uint64(base)
|
||||
for u != 0 {
|
||||
i--
|
||||
a[i] = digits[u%b]
|
||||
u /= b
|
||||
}
|
||||
}
|
||||
|
||||
// add sign, if any
|
||||
if x < 0 && signed {
|
||||
i--
|
||||
a[i] = '-'
|
||||
}
|
||||
|
||||
if append_ {
|
||||
d = append(dst, a[i:]...)
|
||||
return
|
||||
}
|
||||
s = string(a[i:])
|
||||
return
|
||||
}
|
||||
|
@ -77,8 +77,8 @@ func TestItoa(t *testing.T) {
|
||||
t.Errorf("FormatUint(%v, %v) = %v want %v",
|
||||
test.in, test.base, s, test.out)
|
||||
}
|
||||
x := AppendUint([]byte("abc"), uint64(test.in), test.base)
|
||||
if string(x) != "abc"+test.out {
|
||||
x := AppendUint(nil, uint64(test.in), test.base)
|
||||
if string(x) != test.out {
|
||||
t.Errorf("AppendUint(%q, %v, %v) = %q want %v",
|
||||
"abc", uint64(test.in), test.base, x, test.out)
|
||||
}
|
||||
@ -124,3 +124,37 @@ func TestUitoa(t *testing.T) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFormatInt(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range itob64tests {
|
||||
FormatInt(test.in, test.base)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAppendInt(b *testing.B) {
|
||||
dst := make([]byte, 0, 30)
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range itob64tests {
|
||||
AppendInt(dst, test.in, test.base)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFormatUint(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range uitob64tests {
|
||||
FormatUint(test.in, test.base)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAppendUint(b *testing.B) {
|
||||
dst := make([]byte, 0, 30)
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range uitob64tests {
|
||||
AppendUint(dst, test.in, test.base)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user