]> Cypherpunks repositories - gostls13.git/commitdiff
strconv: speed up atoi for common cases
authorMartin Möhrmann <martisch@uos.de>
Tue, 6 Jan 2015 18:48:31 +0000 (19:48 +0100)
committerRobert Griesemer <gri@golang.org>
Thu, 8 Jan 2015 20:58:26 +0000 (20:58 +0000)
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>
src/strconv/atoi.go

index 9ecec5a58b9303a9a05ff1b610e021c839862904..965e3a218fdb93e30371352e4b708a177f052e52 100644 (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