Fix bootstrap/PR63632
[official-gcc.git] / libgo / go / strconv / atoi.go
blobcbf0380ec829e5a9f13cef27d442a722dccee639
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(^uint(0)>>63)
36 // IntSize is the size in bits of an int or uint value.
37 const IntSize = intSize
39 // Return the first number n such that n*base >= 1<<64.
40 func cutoff64(base int) uint64 {
41 if base < 2 {
42 return 0
44 return (1<<64-1)/uint64(base) + 1
47 // ParseUint is like ParseInt but for unsigned numbers.
48 func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
49 var cutoff, maxVal uint64
51 if bitSize == 0 {
52 bitSize = int(IntSize)
55 s0 := s
56 switch {
57 case len(s) < 1:
58 err = ErrSyntax
59 goto Error
61 case 2 <= base && base <= 36:
62 // valid base; nothing to do
64 case base == 0:
65 // Look for octal, hex prefix.
66 switch {
67 case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
68 base = 16
69 s = s[2:]
70 if len(s) < 1 {
71 err = ErrSyntax
72 goto Error
74 case s[0] == '0':
75 base = 8
76 default:
77 base = 10
80 default:
81 err = errors.New("invalid base " + Itoa(base))
82 goto Error
85 n = 0
86 cutoff = cutoff64(base)
87 maxVal = 1<<uint(bitSize) - 1
89 for i := 0; i < len(s); i++ {
90 var v byte
91 d := s[i]
92 switch {
93 case '0' <= d && d <= '9':
94 v = d - '0'
95 case 'a' <= d && d <= 'z':
96 v = d - 'a' + 10
97 case 'A' <= d && d <= 'Z':
98 v = d - 'A' + 10
99 default:
100 n = 0
101 err = ErrSyntax
102 goto Error
104 if int(v) >= base {
105 n = 0
106 err = ErrSyntax
107 goto Error
110 if n >= cutoff {
111 // n*base overflows
112 n = 1<<64 - 1
113 err = ErrRange
114 goto Error
116 n *= uint64(base)
118 n1 := n + uint64(v)
119 if n1 < n || n1 > maxVal {
120 // n+v overflows
121 n = 1<<64 - 1
122 err = ErrRange
123 goto Error
125 n = n1
128 return n, nil
130 Error:
131 return n, &NumError{"ParseUint", s0, err}
134 // ParseInt interprets a string s in the given base (2 to 36) and
135 // returns the corresponding value i. If base == 0, the base is
136 // implied by the string's prefix: base 16 for "0x", base 8 for
137 // "0", and base 10 otherwise.
139 // The bitSize argument specifies the integer type
140 // that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
141 // correspond to int, int8, int16, int32, and int64.
143 // The errors that ParseInt returns have concrete type *NumError
144 // and include err.Num = s. If s is empty or contains invalid
145 // digits, err.Err = ErrSyntax and the returned value is 0;
146 // if the value corresponding to s cannot be represented by a
147 // signed integer of the given size, err.Err = ErrRange and the
148 // returned value is the maximum magnitude integer of the
149 // appropriate bitSize and sign.
150 func ParseInt(s string, base int, bitSize int) (i int64, err error) {
151 const fnParseInt = "ParseInt"
153 if bitSize == 0 {
154 bitSize = int(IntSize)
157 // Empty string bad.
158 if len(s) == 0 {
159 return 0, syntaxError(fnParseInt, s)
162 // Pick off leading sign.
163 s0 := s
164 neg := false
165 if s[0] == '+' {
166 s = s[1:]
167 } else if s[0] == '-' {
168 neg = true
169 s = s[1:]
172 // Convert unsigned and check range.
173 var un uint64
174 un, err = ParseUint(s, base, bitSize)
175 if err != nil && err.(*NumError).Err != ErrRange {
176 err.(*NumError).Func = fnParseInt
177 err.(*NumError).Num = s0
178 return 0, err
180 cutoff := uint64(1 << uint(bitSize-1))
181 if !neg && un >= cutoff {
182 return int64(cutoff - 1), rangeError(fnParseInt, s0)
184 if neg && un > cutoff {
185 return -int64(cutoff), rangeError(fnParseInt, s0)
187 n := int64(un)
188 if neg {
189 n = -n
191 return n, nil
194 // Atoi is shorthand for ParseInt(s, 10, 0).
195 func Atoi(s string) (i int, err error) {
196 i64, err := ParseInt(s, 10, 0)
197 return int(i64), err