mirror of
https://github.com/golang/go
synced 2024-11-18 16:54:43 -07:00
strconv: use bounded bits.TrailingZeros instead of shifts table
The strconv shifts table is 320 bytes (amd64) and is present in many binaries since integer formatting is very common. Instead of using a precalculated table with shift amounts use a bounded bits.TrailingZeros to determine the shift amount to format numbers in a base that is a power of 2. amd64: name old time/op new time/op delta AppendUint 379ns ± 1% 286ns ± 2% -24.62% (p=0.000 n=20+19) Change-Id: Ib94d9b033321b41e975868943c7fcd9428c5111e Reviewed-on: https://go-review.googlesource.com/110478 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
f8ef6ed24a
commit
d29ec40e19
@ -64,7 +64,7 @@ var pkgDeps = map[string][]string{
|
||||
"math/bits": {},
|
||||
"math/cmplx": {"math"},
|
||||
"math/rand": {"L0", "math"},
|
||||
"strconv": {"L0", "unicode/utf8", "math"},
|
||||
"strconv": {"L0", "unicode/utf8", "math", "math/bits"},
|
||||
"unicode/utf16": {},
|
||||
"unicode/utf8": {},
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
package strconv
|
||||
|
||||
import "math/bits"
|
||||
|
||||
const fastSmalls = true // enable fast path for small integers
|
||||
|
||||
// FormatUint returns the string representation of i in the given base,
|
||||
@ -79,14 +81,6 @@ const host32bit = ^uint(0)>>32 == 0
|
||||
|
||||
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 neg is set, u is treated as negative int64 value. If append_ is
|
||||
// set, the string is appended to dst and the resulting byte slice is
|
||||
@ -158,14 +152,17 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
|
||||
a[i] = smallsString[is]
|
||||
}
|
||||
|
||||
} else if s := shifts[base]; s > 0 {
|
||||
// base is power of 2: use shifts and masks instead of / and %
|
||||
} else if isPowerOfTwo(base) {
|
||||
// It is known that base is a power of two and
|
||||
// 2 <= base <= len(digits).
|
||||
// Use shifts and masks instead of / and %.
|
||||
shift := uint(bits.TrailingZeros(uint(base))) & 31
|
||||
b := uint64(base)
|
||||
m := uint(base) - 1 // == 1<<s - 1
|
||||
m := uint(base) - 1 // == 1<<shift - 1
|
||||
for u >= b {
|
||||
i--
|
||||
a[i] = digits[uint(u)&m]
|
||||
u >>= s
|
||||
u >>= shift
|
||||
}
|
||||
// u < base
|
||||
i--
|
||||
@ -200,3 +197,7 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
|
||||
s = string(a[i:])
|
||||
return
|
||||
}
|
||||
|
||||
func isPowerOfTwo(x int) bool {
|
||||
return x&(x-1) == 0
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user