github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/src/strconv/atoi.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package strconv 6 7 import "errors" 8 9 // ErrRange indicates that a value is out of range for the target type. 10 var ErrRange = errors.New("value out of range") 11 12 // ErrSyntax indicates that a value does not have the right syntax for the target type. 13 var ErrSyntax = errors.New("invalid syntax") 14 15 // A NumError records a failed conversion. 16 type NumError struct { 17 Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat) 18 Num string // the input 19 Err error // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.) 20 } 21 22 func (e *NumError) Error() string { 23 return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error() 24 } 25 26 func syntaxError(fn, str string) *NumError { 27 return &NumError{fn, str, ErrSyntax} 28 } 29 30 func rangeError(fn, str string) *NumError { 31 return &NumError{fn, str, ErrRange} 32 } 33 34 func baseError(fn, str string, base int) *NumError { 35 return &NumError{fn, str, errors.New("invalid base " + Itoa(base))} 36 } 37 38 func bitSizeError(fn, str string, bitSize int) *NumError { 39 return &NumError{fn, str, errors.New("invalid bit size " + Itoa(bitSize))} 40 } 41 42 const intSize = 32 << (^uint(0) >> 63) 43 44 // IntSize is the size in bits of an int or uint value. 45 const IntSize = intSize 46 47 const maxUint64 = (1<<64 - 1) 48 49 // ParseUint is like ParseInt but for unsigned numbers. 50 func ParseUint(s string, base int, bitSize int) (uint64, error) { 51 const fnParseUint = "ParseUint" 52 53 if len(s) == 0 { 54 return 0, syntaxError(fnParseUint, s) 55 } 56 57 s0 := s 58 switch { 59 case 2 <= base && base <= 36: 60 // valid base; nothing to do 61 62 case base == 0: 63 // Look for octal, hex prefix. 64 switch { 65 case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'): 66 if len(s) < 3 { 67 return 0, syntaxError(fnParseUint, s0) 68 } 69 base = 16 70 s = s[2:] 71 case s[0] == '0': 72 base = 8 73 s = s[1:] 74 default: 75 base = 10 76 } 77 78 default: 79 return 0, baseError(fnParseUint, s0, base) 80 } 81 82 if bitSize == 0 { 83 bitSize = int(IntSize) 84 } else if bitSize < 0 || bitSize > 64 { 85 return 0, bitSizeError(fnParseUint, s0, bitSize) 86 } 87 88 // Cutoff is the smallest number such that cutoff*base > maxUint64. 89 // Use compile-time constants for common cases. 90 var cutoff uint64 91 switch base { 92 case 10: 93 cutoff = maxUint64/10 + 1 94 case 16: 95 cutoff = maxUint64/16 + 1 96 default: 97 cutoff = maxUint64/uint64(base) + 1 98 } 99 100 maxVal := uint64(1)<<uint(bitSize) - 1 101 102 var n uint64 103 for _, c := range []byte(s) { 104 var d byte 105 switch { 106 case '0' <= c && c <= '9': 107 d = c - '0' 108 case 'a' <= c && c <= 'z': 109 d = c - 'a' + 10 110 case 'A' <= c && c <= 'Z': 111 d = c - 'A' + 10 112 default: 113 return 0, syntaxError(fnParseUint, s0) 114 } 115 116 if d >= byte(base) { 117 return 0, syntaxError(fnParseUint, s0) 118 } 119 120 if n >= cutoff { 121 // n*base overflows 122 return maxVal, rangeError(fnParseUint, s0) 123 } 124 n *= uint64(base) 125 126 n1 := n + uint64(d) 127 if n1 < n || n1 > maxVal { 128 // n+v overflows 129 return maxVal, rangeError(fnParseUint, s0) 130 } 131 n = n1 132 } 133 134 return n, nil 135 } 136 137 // ParseInt interprets a string s in the given base (0, 2 to 36) and 138 // bit size (0 to 64) and returns the corresponding value i. 139 // 140 // If base == 0, the base is implied by the string's prefix: 141 // base 16 for "0x", base 8 for "0", and base 10 otherwise. 142 // For bases 1, below 0 or above 36 an error is returned. 143 // 144 // The bitSize argument specifies the integer type 145 // that the result must fit into. Bit sizes 0, 8, 16, 32, and 64 146 // correspond to int, int8, int16, int32, and int64. 147 // For a bitSize below 0 or above 64 an error is returned. 148 // 149 // The errors that ParseInt returns have concrete type *NumError 150 // and include err.Num = s. If s is empty or contains invalid 151 // digits, err.Err = ErrSyntax and the returned value is 0; 152 // if the value corresponding to s cannot be represented by a 153 // signed integer of the given size, err.Err = ErrRange and the 154 // returned value is the maximum magnitude integer of the 155 // appropriate bitSize and sign. 156 func ParseInt(s string, base int, bitSize int) (i int64, err error) { 157 const fnParseInt = "ParseInt" 158 159 // Empty string bad. 160 if len(s) == 0 { 161 return 0, syntaxError(fnParseInt, s) 162 } 163 164 // Pick off leading sign. 165 s0 := s 166 neg := false 167 if s[0] == '+' { 168 s = s[1:] 169 } else if s[0] == '-' { 170 neg = true 171 s = s[1:] 172 } 173 174 // Convert unsigned and check range. 175 var un uint64 176 un, err = ParseUint(s, base, bitSize) 177 if err != nil && err.(*NumError).Err != ErrRange { 178 err.(*NumError).Func = fnParseInt 179 err.(*NumError).Num = s0 180 return 0, err 181 } 182 183 if bitSize == 0 { 184 bitSize = int(IntSize) 185 } 186 187 cutoff := uint64(1 << uint(bitSize-1)) 188 if !neg && un >= cutoff { 189 return int64(cutoff - 1), rangeError(fnParseInt, s0) 190 } 191 if neg && un > cutoff { 192 return -int64(cutoff), rangeError(fnParseInt, s0) 193 } 194 n := int64(un) 195 if neg { 196 n = -n 197 } 198 return n, nil 199 } 200 201 // Atoi returns the result of ParseInt(s, 10, 0) converted to type int. 202 func Atoi(s string) (int, error) { 203 const fnAtoi = "Atoi" 204 205 sLen := len(s) 206 if intSize == 32 && (0 < sLen && sLen < 10) || 207 intSize == 64 && (0 < sLen && sLen < 19) { 208 // Fast path for small integers that fit int type. 209 s0 := s 210 if s[0] == '-' || s[0] == '+' { 211 s = s[1:] 212 if len(s) < 1 { 213 return 0, &NumError{fnAtoi, s0, ErrSyntax} 214 } 215 } 216 217 n := 0 218 for _, ch := range []byte(s) { 219 ch -= '0' 220 if ch > 9 { 221 return 0, &NumError{fnAtoi, s0, ErrSyntax} 222 } 223 n = n*10 + int(ch) 224 } 225 if s0[0] == '-' { 226 n = -n 227 } 228 return n, nil 229 } 230 231 // Slow path for invalid or big integers. 232 i64, err := ParseInt(s, 10, 0) 233 if nerr, ok := err.(*NumError); ok { 234 nerr.Func = fnAtoi 235 } 236 return int(i64), err 237 }