2008-11-17 13:34:03 -07:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package strconv
|
2009-08-12 14:18:37 -06:00
|
|
|
|
2011-11-01 20:05:34 -06:00
|
|
|
import "errors"
|
2009-06-25 21:24:55 -06:00
|
|
|
|
2011-10-27 20:46:31 -06:00
|
|
|
// ErrRange indicates that a value is out of range for the target type.
|
2011-11-01 20:05:34 -06:00
|
|
|
var ErrRange = errors.New("value out of range")
|
2011-10-27 20:46:31 -06:00
|
|
|
|
|
|
|
// ErrSyntax indicates that a value does not have the right syntax for the target type.
|
2011-11-01 20:05:34 -06:00
|
|
|
var ErrSyntax = errors.New("invalid syntax")
|
2011-10-27 20:46:31 -06:00
|
|
|
|
|
|
|
// A NumError records a failed conversion.
|
2009-06-25 21:24:55 -06:00
|
|
|
type NumError struct {
|
2011-12-13 11:42:05 -07:00
|
|
|
Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat)
|
|
|
|
Num string // the input
|
2017-08-12 13:24:07 -06:00
|
|
|
Err error // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)
|
2009-06-25 21:24:55 -06:00
|
|
|
}
|
|
|
|
|
2011-12-13 11:42:05 -07:00
|
|
|
func (e *NumError) Error() string {
|
2013-02-28 11:08:05 -07:00
|
|
|
return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error()
|
2011-12-13 11:42:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func syntaxError(fn, str string) *NumError {
|
|
|
|
return &NumError{fn, str, ErrSyntax}
|
|
|
|
}
|
|
|
|
|
|
|
|
func rangeError(fn, str string) *NumError {
|
|
|
|
return &NumError{fn, str, ErrRange}
|
|
|
|
}
|
2009-06-25 21:24:55 -06:00
|
|
|
|
2017-08-12 13:24:07 -06:00
|
|
|
func baseError(fn, str string, base int) *NumError {
|
|
|
|
return &NumError{fn, str, errors.New("invalid base " + Itoa(base))}
|
|
|
|
}
|
|
|
|
|
2017-08-12 13:02:43 -06:00
|
|
|
func bitSizeError(fn, str string, bitSize int) *NumError {
|
|
|
|
return &NumError{fn, str, errors.New("invalid bit size " + Itoa(bitSize))}
|
|
|
|
}
|
|
|
|
|
2014-07-31 14:54:42 -06:00
|
|
|
const intSize = 32 << (^uint(0) >> 63)
|
2009-10-07 12:55:06 -06:00
|
|
|
|
2013-08-01 09:34:25 -06:00
|
|
|
// IntSize is the size in bits of an int or uint value.
|
|
|
|
const IntSize = intSize
|
2008-11-17 13:34:03 -07:00
|
|
|
|
2015-01-06 11:48:31 -07:00
|
|
|
const maxUint64 = (1<<64 - 1)
|
2008-11-17 13:34:03 -07:00
|
|
|
|
2011-12-05 13:48:21 -07:00
|
|
|
// ParseUint is like ParseInt but for unsigned numbers.
|
2016-02-28 16:52:49 -07:00
|
|
|
func ParseUint(s string, base int, bitSize int) (uint64, error) {
|
2017-08-12 13:24:07 -06:00
|
|
|
const fnParseUint = "ParseUint"
|
|
|
|
|
2017-08-13 05:00:33 -06:00
|
|
|
if len(s) == 0 {
|
2017-08-12 13:24:07 -06:00
|
|
|
return 0, syntaxError(fnParseUint, s)
|
2017-08-13 05:00:33 -06:00
|
|
|
}
|
2009-10-12 00:46:11 -06:00
|
|
|
|
2017-08-13 05:00:33 -06:00
|
|
|
s0 := s
|
|
|
|
switch {
|
2012-08-20 06:30:04 -06:00
|
|
|
case 2 <= base && base <= 36:
|
2009-10-12 00:46:11 -06:00
|
|
|
// valid base; nothing to do
|
|
|
|
|
2012-08-20 06:30:04 -06:00
|
|
|
case base == 0:
|
2009-10-12 00:46:11 -06:00
|
|
|
// Look for octal, hex prefix.
|
|
|
|
switch {
|
|
|
|
case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
|
2015-01-06 11:48:31 -07:00
|
|
|
if len(s) < 3 {
|
2017-08-13 05:00:33 -06:00
|
|
|
return 0, syntaxError(fnParseUint, s0)
|
2009-10-12 00:46:11 -06:00
|
|
|
}
|
2015-01-06 11:48:31 -07:00
|
|
|
base = 16
|
2017-08-13 05:00:33 -06:00
|
|
|
s = s[2:]
|
2009-10-12 00:46:11 -06:00
|
|
|
case s[0] == '0':
|
2012-08-20 06:30:04 -06:00
|
|
|
base = 8
|
2017-08-13 05:00:33 -06:00
|
|
|
s = s[1:]
|
2009-10-12 00:46:11 -06:00
|
|
|
default:
|
2012-08-20 06:30:04 -06:00
|
|
|
base = 10
|
2009-10-12 00:46:11 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2017-08-13 05:00:33 -06:00
|
|
|
return 0, baseError(fnParseUint, s0, base)
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
2008-11-18 18:12:07 -07:00
|
|
|
|
2017-08-12 13:02:43 -06:00
|
|
|
if bitSize == 0 {
|
|
|
|
bitSize = int(IntSize)
|
|
|
|
} else if bitSize < 0 || bitSize > 64 {
|
|
|
|
return 0, bitSizeError(fnParseUint, s0, bitSize)
|
|
|
|
}
|
|
|
|
|
2015-01-06 11:48:31 -07:00
|
|
|
// Cutoff is the smallest number such that cutoff*base > maxUint64.
|
|
|
|
// Use compile-time constants for common cases.
|
2017-08-13 05:00:33 -06:00
|
|
|
var cutoff uint64
|
2015-01-06 11:48:31 -07:00
|
|
|
switch base {
|
|
|
|
case 10:
|
|
|
|
cutoff = maxUint64/10 + 1
|
|
|
|
case 16:
|
|
|
|
cutoff = maxUint64/16 + 1
|
|
|
|
default:
|
|
|
|
cutoff = maxUint64/uint64(base) + 1
|
|
|
|
}
|
|
|
|
|
2017-08-13 05:00:33 -06:00
|
|
|
maxVal := uint64(1)<<uint(bitSize) - 1
|
2008-11-17 13:34:03 -07:00
|
|
|
|
2017-08-13 05:00:33 -06:00
|
|
|
var n uint64
|
|
|
|
for _, c := range []byte(s) {
|
|
|
|
var d byte
|
2009-02-16 21:44:21 -07:00
|
|
|
switch {
|
2017-08-13 05:00:33 -06:00
|
|
|
case '0' <= c && c <= '9':
|
|
|
|
d = c - '0'
|
|
|
|
case 'a' <= c && c <= 'z':
|
|
|
|
d = c - 'a' + 10
|
|
|
|
case 'A' <= c && c <= 'Z':
|
|
|
|
d = c - 'A' + 10
|
2009-02-16 21:44:21 -07:00
|
|
|
default:
|
2017-08-13 05:00:33 -06:00
|
|
|
return 0, syntaxError(fnParseUint, s0)
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
2017-08-13 05:00:33 -06:00
|
|
|
|
|
|
|
if d >= byte(base) {
|
|
|
|
return 0, syntaxError(fnParseUint, s0)
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
2009-02-16 21:44:21 -07:00
|
|
|
|
|
|
|
if n >= cutoff {
|
2012-08-20 06:30:04 -06:00
|
|
|
// n*base overflows
|
2017-08-13 05:00:33 -06:00
|
|
|
return maxVal, rangeError(fnParseUint, s0)
|
2009-02-16 21:44:21 -07:00
|
|
|
}
|
2012-08-20 06:30:04 -06:00
|
|
|
n *= uint64(base)
|
2009-02-16 21:44:21 -07:00
|
|
|
|
2017-08-13 05:00:33 -06:00
|
|
|
n1 := n + uint64(d)
|
2011-12-05 13:48:21 -07:00
|
|
|
if n1 < n || n1 > maxVal {
|
2009-02-16 21:44:21 -07:00
|
|
|
// n+v overflows
|
2017-08-13 05:00:33 -06:00
|
|
|
return maxVal, rangeError(fnParseUint, s0)
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
2009-12-15 16:40:16 -07:00
|
|
|
n = n1
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
2009-02-16 21:44:21 -07:00
|
|
|
|
2009-12-15 16:40:16 -07:00
|
|
|
return n, nil
|
2009-02-16 21:44:21 -07:00
|
|
|
}
|
|
|
|
|
2017-08-12 13:02:43 -06:00
|
|
|
// ParseInt interprets a string s in the given base (0, 2 to 36) and
|
|
|
|
// bit size (0 to 64) and returns the corresponding value i.
|
|
|
|
//
|
|
|
|
// If base == 0, the base is implied by the string's prefix:
|
|
|
|
// base 16 for "0x", base 8 for "0", and base 10 otherwise.
|
|
|
|
// For bases 1, below 0 or above 36 an error is returned.
|
2009-03-05 16:29:04 -07:00
|
|
|
//
|
2011-12-05 13:48:21 -07:00
|
|
|
// The bitSize argument specifies the integer type
|
2016-03-01 16:21:55 -07:00
|
|
|
// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
|
2011-12-05 13:48:21 -07:00
|
|
|
// correspond to int, int8, int16, int32, and int64.
|
2017-08-12 13:02:43 -06:00
|
|
|
// For a bitSize below 0 or above 64 an error is returned.
|
2011-12-05 13:48:21 -07:00
|
|
|
//
|
|
|
|
// The errors that ParseInt returns have concrete type *NumError
|
2016-03-01 16:21:55 -07:00
|
|
|
// and include err.Num = s. If s is empty or contains invalid
|
2014-03-06 19:23:50 -07:00
|
|
|
// digits, err.Err = ErrSyntax and the returned value is 0;
|
|
|
|
// if the value corresponding to s cannot be represented by a
|
|
|
|
// signed integer of the given size, err.Err = ErrRange and the
|
|
|
|
// returned value is the maximum magnitude integer of the
|
|
|
|
// appropriate bitSize and sign.
|
2011-12-05 13:48:21 -07:00
|
|
|
func ParseInt(s string, base int, bitSize int) (i int64, err error) {
|
2011-12-13 11:42:05 -07:00
|
|
|
const fnParseInt = "ParseInt"
|
|
|
|
|
2009-02-16 21:44:21 -07:00
|
|
|
// Empty string bad.
|
2008-11-17 13:34:03 -07:00
|
|
|
if len(s) == 0 {
|
2011-12-13 11:42:05 -07:00
|
|
|
return 0, syntaxError(fnParseInt, s)
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
|
|
|
|
2009-02-16 21:44:21 -07:00
|
|
|
// Pick off leading sign.
|
2009-12-15 16:40:16 -07:00
|
|
|
s0 := s
|
|
|
|
neg := false
|
2008-11-17 13:34:03 -07:00
|
|
|
if s[0] == '+' {
|
2009-11-20 12:45:05 -07:00
|
|
|
s = s[1:]
|
2008-11-17 13:34:03 -07:00
|
|
|
} else if s[0] == '-' {
|
2009-12-15 16:40:16 -07:00
|
|
|
neg = true
|
|
|
|
s = s[1:]
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
|
|
|
|
2009-02-16 21:44:21 -07:00
|
|
|
// Convert unsigned and check range.
|
2009-12-15 16:40:16 -07:00
|
|
|
var un uint64
|
2011-12-05 13:48:21 -07:00
|
|
|
un, err = ParseUint(s, base, bitSize)
|
2011-11-01 20:05:34 -06:00
|
|
|
if err != nil && err.(*NumError).Err != ErrRange {
|
2011-12-13 11:42:05 -07:00
|
|
|
err.(*NumError).Func = fnParseInt
|
2009-12-15 16:40:16 -07:00
|
|
|
err.(*NumError).Num = s0
|
|
|
|
return 0, err
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
2017-08-12 13:02:43 -06:00
|
|
|
|
|
|
|
if bitSize == 0 {
|
|
|
|
bitSize = int(IntSize)
|
|
|
|
}
|
|
|
|
|
2011-12-05 13:48:21 -07:00
|
|
|
cutoff := uint64(1 << uint(bitSize-1))
|
|
|
|
if !neg && un >= cutoff {
|
2011-12-13 11:42:05 -07:00
|
|
|
return int64(cutoff - 1), rangeError(fnParseInt, s0)
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
2011-12-05 13:48:21 -07:00
|
|
|
if neg && un > cutoff {
|
2011-12-13 11:42:05 -07:00
|
|
|
return -int64(cutoff), rangeError(fnParseInt, s0)
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
2009-12-15 16:40:16 -07:00
|
|
|
n := int64(un)
|
2008-11-17 13:34:03 -07:00
|
|
|
if neg {
|
2009-11-09 13:07:39 -07:00
|
|
|
n = -n
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
2009-12-15 16:40:16 -07:00
|
|
|
return n, nil
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
|
|
|
|
2016-06-19 14:39:58 -06:00
|
|
|
// Atoi returns the result of ParseInt(s, 10, 0) converted to type int.
|
2016-02-28 16:52:49 -07:00
|
|
|
func Atoi(s string) (int, error) {
|
2016-09-03 13:01:27 -06:00
|
|
|
const fnAtoi = "Atoi"
|
2017-06-02 10:16:19 -06:00
|
|
|
|
|
|
|
sLen := len(s)
|
|
|
|
if intSize == 32 && (0 < sLen && sLen < 10) ||
|
|
|
|
intSize == 64 && (0 < sLen && sLen < 19) {
|
|
|
|
// Fast path for small integers that fit int type.
|
|
|
|
s0 := s
|
|
|
|
if s[0] == '-' || s[0] == '+' {
|
|
|
|
s = s[1:]
|
|
|
|
if len(s) < 1 {
|
|
|
|
return 0, &NumError{fnAtoi, s0, ErrSyntax}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n := 0
|
|
|
|
for _, ch := range []byte(s) {
|
|
|
|
ch -= '0'
|
|
|
|
if ch > 9 {
|
|
|
|
return 0, &NumError{fnAtoi, s0, ErrSyntax}
|
|
|
|
}
|
|
|
|
n = n*10 + int(ch)
|
|
|
|
}
|
|
|
|
if s0[0] == '-' {
|
|
|
|
n = -n
|
|
|
|
}
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Slow path for invalid or big integers.
|
2011-12-05 13:48:21 -07:00
|
|
|
i64, err := ParseInt(s, 10, 0)
|
2016-09-03 13:01:27 -06:00
|
|
|
if nerr, ok := err.(*NumError); ok {
|
|
|
|
nerr.Func = fnAtoi
|
|
|
|
}
|
2011-12-05 13:48:21 -07:00
|
|
|
return int(i64), err
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|