Home | History | Annotate | Download | only in strconv
      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.
      4 
      5 package strconv
      6 
      7 import "errors"
      8 
      9 // ErrRange indicates that a value is out of range for the target type.
     10 var ErrRange = errors.New("value out of range")
     11 
     12 // ErrSyntax indicates that a value does not have the right syntax for the target type.
     13 var ErrSyntax = errors.New("invalid syntax")
     14 
     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.)
     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 // IntSize is the size in bits of an int or uint value.
     45 const IntSize = intSize
     46 
     47 const maxUint64 = (1<<64 - 1)
     48 
     49 // ParseUint is like ParseInt but for unsigned numbers.
     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 		// valid base; nothing to do
     61 
     62 	case base == 0:
     63 		// Look for octal, hex prefix.
     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 	// Cutoff is the smallest number such that cutoff*base > maxUint64.
     89 	// Use compile-time constants for common cases.
     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 			// n*base overflows
    122 			return maxVal, rangeError(fnParseUint, s0)
    123 		}
    124 		n *= uint64(base)
    125 
    126 		n1 := n + uint64(d)
    127 		if n1 < n || n1 > maxVal {
    128 			// n+v overflows
    129 			return maxVal, rangeError(fnParseUint, s0)
    130 		}
    131 		n = n1
    132 	}
    133 
    134 	return n, nil
    135 }
    136 
    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.
    139 //
    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.
    143 //
    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.
    148 //
    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"
    158 
    159 	// Empty string bad.
    160 	if len(s) == 0 {
    161 		return 0, syntaxError(fnParseInt, s)
    162 	}
    163 
    164 	// Pick off leading sign.
    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 	// Convert unsigned and check range.
    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 // Atoi returns the result of ParseInt(s, 10, 0) converted to type int.
    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 		// Fast path for small integers that fit int type.
    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 	// Slow path for invalid or big integers.
    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