Source file
src/strconv/atoi.go
Documentation: strconv
1
2
3
4
5 package strconv
6
7 import "errors"
8
9
10 var ErrRange = errors.New("value out of range")
11
12
13 var ErrSyntax = errors.New("invalid syntax")
14
15
16 type NumError struct {
17 Func string
18 Num string
19 Err error
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
45 const IntSize = intSize
46
47 const maxUint64 = (1<<64 - 1)
48
49
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
61
62 case base == 0:
63
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
89
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
122 return maxVal, rangeError(fnParseUint, s0)
123 }
124 n *= uint64(base)
125
126 n1 := n + uint64(d)
127 if n1 < n || n1 > maxVal {
128
129 return maxVal, rangeError(fnParseUint, s0)
130 }
131 n = n1
132 }
133
134 return n, nil
135 }
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 func ParseInt(s string, base int, bitSize int) (i int64, err error) {
157 const fnParseInt = "ParseInt"
158
159
160 if len(s) == 0 {
161 return 0, syntaxError(fnParseInt, s)
162 }
163
164
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
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
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
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
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 }
238
View as plain text