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.
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 (e.g. ErrRange, ErrSyntax, etc.)
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 func baseError(fn
, str
string, base
int) *NumError
{
35 return &NumError
{fn
, str
, errors
.New("invalid base " + Itoa(base
))}
38 func bitSizeError(fn
, str
string, bitSize
int) *NumError
{
39 return &NumError
{fn
, str
, errors
.New("invalid bit size " + Itoa(bitSize
))}
42 const intSize
= 32 << (^uint(0) >> 63)
44 // IntSize is the size in bits of an int or uint value.
45 const IntSize
= intSize
47 const maxUint64
= (1<<64 - 1)
49 // ParseUint is like ParseInt but for unsigned numbers.
50 func ParseUint(s
string, base
int, bitSize
int) (uint64, error
) {
51 const fnParseUint
= "ParseUint"
54 return 0, syntaxError(fnParseUint
, s
)
59 case 2 <= base
&& base
<= 36:
60 // valid base; nothing to do
63 // Look for octal, hex prefix.
65 case s
[0] == '0' && len(s
) > 1 && (s
[1] == 'x' || s
[1] == 'X'):
67 return 0, syntaxError(fnParseUint
, s0
)
79 return 0, baseError(fnParseUint
, s0
, base
)
83 bitSize
= int(IntSize
)
84 } else if bitSize
< 0 || bitSize
> 64 {
85 return 0, bitSizeError(fnParseUint
, s0
, bitSize
)
88 // Cutoff is the smallest number such that cutoff*base > maxUint64.
89 // Use compile-time constants for common cases.
93 cutoff
= maxUint64
/10 + 1
95 cutoff
= maxUint64
/16 + 1
97 cutoff
= maxUint64
/uint64(base
) + 1
100 maxVal
:= uint64(1)<<uint(bitSize
) - 1
103 for _
, c
:= range []byte(s
) {
106 case '0' <= c
&& c
<= '9':
108 case 'a' <= c
&& c
<= 'z':
110 case 'A' <= c
&& c
<= 'Z':
113 return 0, syntaxError(fnParseUint
, s0
)
117 return 0, syntaxError(fnParseUint
, s0
)
122 return maxVal
, rangeError(fnParseUint
, s0
)
127 if n1
< n || n1
> maxVal
{
129 return maxVal
, rangeError(fnParseUint
, s0
)
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.
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.
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.
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"
161 return 0, syntaxError(fnParseInt
, s
)
164 // Pick off leading sign.
169 } else if s
[0] == '-' {
174 // Convert unsigned and check range.
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
184 bitSize
= int(IntSize
)
187 cutoff
:= uint64(1 << uint(bitSize
-1))
188 if !neg
&& un
>= cutoff
{
189 return int64(cutoff
- 1), rangeError(fnParseInt
, s0
)
191 if neg
&& un
> cutoff
{
192 return -int64(cutoff
), rangeError(fnParseInt
, s0
)
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"
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.
210 if s
[0] == '-' || s
[0] == '+' {
213 return 0, &NumError
{fnAtoi
, s0
, ErrSyntax
}
218 for _
, ch
:= range []byte(s
) {
221 return 0, &NumError
{fnAtoi
, s0
, ErrSyntax
}
231 // Slow path for invalid or big integers.
232 i64
, err
:= ParseInt(s
, 10, 0)
233 if nerr
, ok
:= err
.(*NumError
); ok
{