github.com/remobjects/goldbaselibrary@v0.0.0-20230924164425-d458680a936b/Source/Gold/strconv/atoi_elements.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 // lower(c) is a lower-case letter if and only if 10 // c is either that lower-case letter or the equivalent upper-case letter. 11 // Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. 12 // Note that lower of non-letters can produce other non-letters. 13 func lower(c byte) byte { 14 return c | ('x' - 'X') 15 } 16 17 // ErrRange indicates that a value is out of range for the target type. 18 var ErrRange = errors.New("value out of range") 19 20 // ErrSyntax indicates that a value does not have the right syntax for the target type. 21 var ErrSyntax = errors.New("invalid syntax") 22 23 // A NumError records a failed conversion. 24 type NumError struct { 25 Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat) 26 Num string // the input 27 Err error // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.) 28 } 29 30 func (e *NumError) Error() string { 31 return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error() 32 } 33 34 func syntaxError(fn, str string) *NumError { 35 return &NumError{fn, str, ErrSyntax} 36 } 37 38 func rangeError(fn, str string) *NumError { 39 return &NumError{fn, str, ErrRange} 40 } 41 42 func baseError(fn, str string, base int) *NumError { 43 return &NumError{fn, str, errors.New("invalid base " + Itoa(base))} 44 } 45 46 func bitSizeError(fn, str string, bitSize int) *NumError { 47 return &NumError{fn, str, errors.New("invalid bit size " + Itoa(bitSize))} 48 } 49 50 //const intSize = 32 << (^uint(0) >> 63) 51 // elements change 52 const intSize = 64 53 54 // IntSize is the size in bits of an int or uint value. 55 const IntSize = intSize 56 57 //const maxUint64 = 1<<64 - 1 58 // elements change 59 const maxUint64 = 18446744073709551615 60 61 // ParseUint is like ParseInt but for unsigned numbers. 62 func ParseUint(s string, base int, bitSize int) (uint64, error) { 63 const fnParseUint = "ParseUint" 64 65 if s == "" || !underscoreOK(s) { 66 return 0, syntaxError(fnParseUint, s) 67 } 68 69 base0 := base == 0 70 71 s0 := s 72 switch { 73 case 2 <= base && base <= 36: 74 // valid base; nothing to do 75 76 case base == 0: 77 // Look for octal, hex prefix. 78 base = 10 79 if s[0] == '0' { 80 switch { 81 case len(s) >= 3 && lower(s[1]) == 'b': 82 base = 2 83 s = s[2:] 84 case len(s) >= 3 && lower(s[1]) == 'o': 85 base = 8 86 s = s[2:] 87 case len(s) >= 3 && lower(s[1]) == 'x': 88 base = 16 89 s = s[2:] 90 default: 91 base = 8 92 s = s[1:] 93 } 94 } 95 96 default: 97 return 0, baseError(fnParseUint, s0, base) 98 } 99 100 if bitSize == 0 { 101 bitSize = int(IntSize) 102 } else if bitSize < 0 || bitSize > 64 { 103 return 0, bitSizeError(fnParseUint, s0, bitSize) 104 } 105 106 // Cutoff is the smallest number such that cutoff*base > maxUint64. 107 // Use compile-time constants for common cases. 108 var cutoff uint64 109 switch base { 110 case 10: 111 cutoff = maxUint64/10 + 1 112 case 16: 113 cutoff = maxUint64/16 + 1 114 default: 115 cutoff = maxUint64/uint64(base) + 1 116 } 117 118 maxVal := uint64(1)<<uint(bitSize) - 1 119 120 var n uint64 121 for _, c := range []byte(s) { 122 var d byte 123 switch { 124 case c == '_' && base0: 125 // underscoreOK already called 126 continue 127 case '0' <= c && c <= '9': 128 d = c - '0' 129 case 'a' <= lower(c) && lower(c) <= 'z': 130 d = lower(c) - 'a' + 10 131 default: 132 return 0, syntaxError(fnParseUint, s0) 133 } 134 135 if d >= byte(base) { 136 return 0, syntaxError(fnParseUint, s0) 137 } 138 139 if n >= cutoff { 140 // n*base overflows 141 return maxVal, rangeError(fnParseUint, s0) 142 } 143 n *= uint64(base) 144 145 n1 := n + uint64(d) 146 if n1 < n || n1 > maxVal { 147 // n+v overflows 148 return maxVal, rangeError(fnParseUint, s0) 149 } 150 n = n1 151 } 152 153 return n, nil 154 } 155 156 // ParseInt interprets a string s in the given base (0, 2 to 36) and 157 // bit size (0 to 64) and returns the corresponding value i. 158 // 159 // If base == 0, the base is implied by the string's prefix: 160 // base 2 for "0b", base 8 for "0" or "0o", base 16 for "0x", 161 // and base 10 otherwise. Also, for base == 0 only, underscore 162 // characters are permitted per the Go integer literal syntax. 163 // If base is below 0, is 1, or is above 36, an error is returned. 164 // 165 // The bitSize argument specifies the integer type 166 // that the result must fit into. Bit sizes 0, 8, 16, 32, and 64 167 // correspond to int, int8, int16, int32, and int64. 168 // If bitSize is below 0 or above 64, an error is returned. 169 // 170 // The errors that ParseInt returns have concrete type *NumError 171 // and include err.Num = s. If s is empty or contains invalid 172 // digits, err.Err = ErrSyntax and the returned value is 0; 173 // if the value corresponding to s cannot be represented by a 174 // signed integer of the given size, err.Err = ErrRange and the 175 // returned value is the maximum magnitude integer of the 176 // appropriate bitSize and sign. 177 func ParseInt(s string, base int, bitSize int) (i int64, err error) { 178 const fnParseInt = "ParseInt" 179 180 if s == "" { 181 return 0, syntaxError(fnParseInt, s) 182 } 183 184 // Pick off leading sign. 185 s0 := s 186 neg := false 187 if s[0] == '+' { 188 s = s[1:] 189 } else if s[0] == '-' { 190 neg = true 191 s = s[1:] 192 } 193 194 // Convert unsigned and check range. 195 var un uint64 196 un, err = ParseUint(s, base, bitSize) 197 if err != nil && err.(*NumError).Err != ErrRange { 198 err.(*NumError).Func = fnParseInt 199 err.(*NumError).Num = s0 200 return 0, err 201 } 202 203 if bitSize == 0 { 204 bitSize = int(IntSize) 205 } 206 207 //cutoff := uint64(1 << uint(bitSize-1)) 208 // elements change 209 cutoff := uint64(1) << uint(bitSize-1) 210 if !neg && un >= cutoff { 211 return int64(cutoff - 1), rangeError(fnParseInt, s0) 212 } 213 if neg && un > cutoff { 214 return -int64(cutoff), rangeError(fnParseInt, s0) 215 } 216 n := int64(un) 217 if neg { 218 n = -n 219 } 220 return n, nil 221 } 222 223 // Atoi is equivalent to ParseInt(s, 10, 0), converted to type int. 224 func Atoi(s string) (int, error) { 225 const fnAtoi = "Atoi" 226 227 sLen := len(s) 228 if intSize == 32 && (0 < sLen && sLen < 10) || 229 intSize == 64 && (0 < sLen && sLen < 19) { 230 // Fast path for small integers that fit int type. 231 s0 := s 232 if s[0] == '-' || s[0] == '+' { 233 s = s[1:] 234 if len(s) < 1 { 235 return 0, &NumError{fnAtoi, s0, ErrSyntax} 236 } 237 } 238 239 n := 0 240 for _, ch := range []byte(s) { 241 ch -= '0' 242 if ch > 9 { 243 return 0, &NumError{fnAtoi, s0, ErrSyntax} 244 } 245 n = n*10 + int(ch) 246 } 247 if s0[0] == '-' { 248 n = -n 249 } 250 return n, nil 251 } 252 253 // Slow path for invalid, big, or underscored integers. 254 i64, err := ParseInt(s, 10, 0) 255 if nerr, ok := err.(*NumError); ok { 256 nerr.Func = fnAtoi 257 } 258 return int(i64), err 259 } 260 261 // underscoreOK reports whether the underscores in s are allowed. 262 // Checking them in this one function lets all the parsers skip over them simply. 263 // Underscore must appear only between digits or between a base prefix and a digit. 264 func underscoreOK(s string) bool { 265 // saw tracks the last character (class) we saw: 266 // ^ for beginning of number, 267 // 0 for a digit or base prefix, 268 // _ for an underscore, 269 // ! for none of the above. 270 saw := '^' 271 i := 0 272 273 // Optional sign. 274 if len(s) >= 1 && (s[0] == '-' || s[0] == '+') { 275 s = s[1:] 276 } 277 278 // Optional base prefix. 279 hex := false 280 if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') { 281 i = 2 282 saw = '0' // base prefix counts as a digit for "underscore as digit separator" 283 hex = lower(s[1]) == 'x' 284 } 285 286 // Number proper. 287 for ; i < len(s); i++ { 288 // Digits are always okay. 289 if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' { 290 saw = '0' 291 continue 292 } 293 // Underscore must follow digit. 294 if s[i] == '_' { 295 if saw != '0' { 296 return false 297 } 298 saw = '_' 299 continue 300 } 301 // Underscore must also be followed by digit. 302 if saw == '_' { 303 return false 304 } 305 // Saw non-digit, non-underscore. 306 saw = '!' 307 } 308 return saw != '_' 309 }