PR tree-optimization/82929
[official-gcc.git] / libgo / go / strconv / atoi.go
blob66df149172d8741ebd30d39f6fd79d9097380391
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.
5 package strconv
7 import "errors"
9 // ErrRange indicates that a value is out of range for the target type.
10 var ErrRange = errors.New("value out of range")
12 // ErrSyntax indicates that a value does not have the right syntax for the target type.
13 var ErrSyntax = errors.New("invalid syntax")
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 (ErrRange, ErrSyntax)
22 func (e *NumError) Error() string {
23 return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error()
26 func syntaxError(fn, str string) *NumError {
27 return &NumError{fn, str, ErrSyntax}
30 func rangeError(fn, str string) *NumError {
31 return &NumError{fn, str, ErrRange}
34 const intSize = 32 << (^uint(0) >> 63)
36 // IntSize is the size in bits of an int or uint value.
37 const IntSize = intSize
39 const maxUint64 = (1<<64 - 1)
41 // ParseUint is like ParseInt but for unsigned numbers.
42 func ParseUint(s string, base int, bitSize int) (uint64, error) {
43 var n uint64
44 var err error
45 var cutoff, maxVal uint64
47 if bitSize == 0 {
48 bitSize = int(IntSize)
51 i := 0
52 switch {
53 case len(s) < 1:
54 err = ErrSyntax
55 goto Error
57 case 2 <= base && base <= 36:
58 // valid base; nothing to do
60 case base == 0:
61 // Look for octal, hex prefix.
62 switch {
63 case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
64 if len(s) < 3 {
65 err = ErrSyntax
66 goto Error
68 base = 16
69 i = 2
70 case s[0] == '0':
71 base = 8
72 i = 1
73 default:
74 base = 10
77 default:
78 err = errors.New("invalid base " + Itoa(base))
79 goto Error
82 // Cutoff is the smallest number such that cutoff*base > maxUint64.
83 // Use compile-time constants for common cases.
84 switch base {
85 case 10:
86 cutoff = maxUint64/10 + 1
87 case 16:
88 cutoff = maxUint64/16 + 1
89 default:
90 cutoff = maxUint64/uint64(base) + 1
93 maxVal = 1<<uint(bitSize) - 1
95 for ; i < len(s); i++ {
96 var v byte
97 d := s[i]
98 switch {
99 case '0' <= d && d <= '9':
100 v = d - '0'
101 case 'a' <= d && d <= 'z':
102 v = d - 'a' + 10
103 case 'A' <= d && d <= 'Z':
104 v = d - 'A' + 10
105 default:
106 n = 0
107 err = ErrSyntax
108 goto Error
110 if v >= byte(base) {
111 n = 0
112 err = ErrSyntax
113 goto Error
116 if n >= cutoff {
117 // n*base overflows
118 n = maxUint64
119 err = ErrRange
120 goto Error
122 n *= uint64(base)
124 n1 := n + uint64(v)
125 if n1 < n || n1 > maxVal {
126 // n+v overflows
127 n = maxUint64
128 err = ErrRange
129 goto Error
131 n = n1
134 return n, nil
136 Error:
137 return n, &NumError{"ParseUint", s, err}
140 // ParseInt interprets a string s in the given base (2 to 36) and
141 // returns the corresponding value i. If base == 0, the base is
142 // implied by the string's prefix: base 16 for "0x", base 8 for
143 // "0", and base 10 otherwise.
145 // The bitSize argument specifies the integer type
146 // that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
147 // correspond to int, int8, int16, int32, and int64.
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"
159 if bitSize == 0 {
160 bitSize = int(IntSize)
163 // Empty string bad.
164 if len(s) == 0 {
165 return 0, syntaxError(fnParseInt, s)
168 // Pick off leading sign.
169 s0 := s
170 neg := false
171 if s[0] == '+' {
172 s = s[1:]
173 } else if s[0] == '-' {
174 neg = true
175 s = s[1:]
178 // Convert unsigned and check range.
179 var un uint64
180 un, err = ParseUint(s, base, bitSize)
181 if err != nil && err.(*NumError).Err != ErrRange {
182 err.(*NumError).Func = fnParseInt
183 err.(*NumError).Num = s0
184 return 0, err
186 cutoff := uint64(1 << uint(bitSize-1))
187 if !neg && un >= cutoff {
188 return int64(cutoff - 1), rangeError(fnParseInt, s0)
190 if neg && un > cutoff {
191 return -int64(cutoff), rangeError(fnParseInt, s0)
193 n := int64(un)
194 if neg {
195 n = -n
197 return n, nil
200 // Atoi returns the result of ParseInt(s, 10, 0) converted to type int.
201 func Atoi(s string) (int, error) {
202 const fnAtoi = "Atoi"
203 i64, err := ParseInt(s, 10, 0)
204 if nerr, ok := err.(*NumError); ok {
205 nerr.Func = fnAtoi
207 return int(i64), err