diff options
| author | Martin Möhrmann <martisch@uos.de> | 2015-01-06 19:48:31 +0100 |
|---|---|---|
| committer | Robert Griesemer <gri@golang.org> | 2015-01-08 20:58:26 +0000 |
| commit | 06ed8f0df76e9b0256de286392d42d1ea7dec809 (patch) | |
| tree | daa3419230a2bb46e88dd6bd211ffca14442a12b /src/strconv | |
| parent | db7fd1c1420d5ef2f874f40c0349b35007568c77 (diff) | |
| download | go-06ed8f0df76e9b0256de286392d42d1ea7dec809.tar.xz | |
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>
Diffstat (limited to 'src/strconv')
| -rw-r--r-- | src/strconv/atoi.go | 40 |
1 files changed, 22 insertions, 18 deletions
diff --git a/src/strconv/atoi.go b/src/strconv/atoi.go index 9ecec5a58b..965e3a218f 100644 --- a/src/strconv/atoi.go +++ b/src/strconv/atoi.go @@ -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 |
