1
0
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:
Martin Möhrmann 2015-01-06 19:48:31 +01:00 committed by Robert Griesemer
parent db7fd1c142
commit 06ed8f0df7

View File

@ -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