mirror of
https://github.com/golang/go
synced 2024-11-18 14:04:45 -07:00
strconv: speed up atoi for common cases
Add compile time constants for bases 10 and 16 instead of computing the cutoff value on every invocation of ParseUint by a division. Reduce usage of slice operations. amd64: benchmark old ns/op new ns/op delta BenchmarkAtoi 44.6 36.0 -19.28% BenchmarkAtoiNeg 44.2 38.9 -11.99% BenchmarkAtoi64 72.5 56.7 -21.79% BenchmarkAtoi64Neg 66.1 58.6 -11.35% 386: benchmark old ns/op new ns/op delta BenchmarkAtoi 86.6 73.0 -15.70% BenchmarkAtoiNeg 86.6 72.3 -16.51% BenchmarkAtoi64 126 108 -14.29% BenchmarkAtoi64Neg 126 108 -14.29% Change-Id: I0a271132120d776c97bb4ed1099793c73e159893 Reviewed-on: https://go-review.googlesource.com/2460 Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
db7fd1c142
commit
06ed8f0df7
@ -36,13 +36,7 @@ const intSize = 32 << (^uint(0) >> 63)
|
||||
// IntSize is the size in bits of an int or uint value.
|
||||
const IntSize = intSize
|
||||
|
||||
// Return the first number n such that n*base >= 1<<64.
|
||||
func cutoff64(base int) uint64 {
|
||||
if base < 2 {
|
||||
return 0
|
||||
}
|
||||
return (1<<64-1)/uint64(base) + 1
|
||||
}
|
||||
const maxUint64 = (1<<64 - 1)
|
||||
|
||||
// ParseUint is like ParseInt but for unsigned numbers.
|
||||
func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
|
||||
@ -52,7 +46,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
|
||||
bitSize = int(IntSize)
|
||||
}
|
||||
|
||||
s0 := s
|
||||
i := 0
|
||||
switch {
|
||||
case len(s) < 1:
|
||||
err = ErrSyntax
|
||||
@ -65,14 +59,15 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
|
||||
// Look for octal, hex prefix.
|
||||
switch {
|
||||
case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
|
||||
base = 16
|
||||
s = s[2:]
|
||||
if len(s) < 1 {
|
||||
if len(s) < 3 {
|
||||
err = ErrSyntax
|
||||
goto Error
|
||||
}
|
||||
base = 16
|
||||
i = 2
|
||||
case s[0] == '0':
|
||||
base = 8
|
||||
i = 1
|
||||
default:
|
||||
base = 10
|
||||
}
|
||||
@ -82,11 +77,20 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
|
||||
goto Error
|
||||
}
|
||||
|
||||
n = 0
|
||||
cutoff = cutoff64(base)
|
||||
// Cutoff is the smallest number such that cutoff*base > maxUint64.
|
||||
// Use compile-time constants for common cases.
|
||||
switch base {
|
||||
case 10:
|
||||
cutoff = maxUint64/10 + 1
|
||||
case 16:
|
||||
cutoff = maxUint64/16 + 1
|
||||
default:
|
||||
cutoff = maxUint64/uint64(base) + 1
|
||||
}
|
||||
|
||||
maxVal = 1<<uint(bitSize) - 1
|
||||
|
||||
for i := 0; i < len(s); i++ {
|
||||
for ; i < len(s); i++ {
|
||||
var v byte
|
||||
d := s[i]
|
||||
switch {
|
||||
@ -101,7 +105,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
|
||||
err = ErrSyntax
|
||||
goto Error
|
||||
}
|
||||
if int(v) >= base {
|
||||
if v >= byte(base) {
|
||||
n = 0
|
||||
err = ErrSyntax
|
||||
goto Error
|
||||
@ -109,7 +113,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
|
||||
|
||||
if n >= cutoff {
|
||||
// n*base overflows
|
||||
n = 1<<64 - 1
|
||||
n = maxUint64
|
||||
err = ErrRange
|
||||
goto Error
|
||||
}
|
||||
@ -118,7 +122,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
|
||||
n1 := n + uint64(v)
|
||||
if n1 < n || n1 > maxVal {
|
||||
// n+v overflows
|
||||
n = 1<<64 - 1
|
||||
n = maxUint64
|
||||
err = ErrRange
|
||||
goto Error
|
||||
}
|
||||
@ -128,7 +132,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
|
||||
return n, nil
|
||||
|
||||
Error:
|
||||
return n, &NumError{"ParseUint", s0, err}
|
||||
return n, &NumError{"ParseUint", s, err}
|
||||
}
|
||||
|
||||
// ParseInt interprets a string s in the given base (2 to 36) and
|
||||
|
Loading…
Reference in New Issue
Block a user