...
Run Format

Source file src/pkg/strconv/atoi.go

     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 (ErrRange, ErrSyntax)
    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	const intSize = 32 << uint(^uint(0)>>63)
    35	
    36	// IntSize is the size in bits of an int or uint value.
    37	const IntSize = intSize
    38	
    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
    43		}
    44		return (1<<64-1)/uint64(base) + 1
    45	}
    46	
    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
    50	
    51		if bitSize == 0 {
    52			bitSize = int(IntSize)
    53		}
    54	
    55		s0 := s
    56		switch {
    57		case len(s) < 1:
    58			err = ErrSyntax
    59			goto Error
    60	
    61		case 2 <= base && base <= 36:
    62			// valid base; nothing to do
    63	
    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
    73				}
    74			case s[0] == '0':
    75				base = 8
    76			default:
    77				base = 10
    78			}
    79	
    80		default:
    81			err = errors.New("invalid base " + Itoa(base))
    82			goto Error
    83		}
    84	
    85		n = 0
    86		cutoff = cutoff64(base)
    87		maxVal = 1<<uint(bitSize) - 1
    88	
    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
   103			}
   104			if int(v) >= base {
   105				n = 0
   106				err = ErrSyntax
   107				goto Error
   108			}
   109	
   110			if n >= cutoff {
   111				// n*base overflows
   112				n = 1<<64 - 1
   113				err = ErrRange
   114				goto Error
   115			}
   116			n *= uint64(base)
   117	
   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
   124			}
   125			n = n1
   126		}
   127	
   128		return n, nil
   129	
   130	Error:
   131		return n, &NumError{"ParseUint", s0, err}
   132	}
   133	
   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.
   138	//
   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.
   142	//
   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"
   152	
   153		if bitSize == 0 {
   154			bitSize = int(IntSize)
   155		}
   156	
   157		// Empty string bad.
   158		if len(s) == 0 {
   159			return 0, syntaxError(fnParseInt, s)
   160		}
   161	
   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:]
   170		}
   171	
   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
   179		}
   180		cutoff := uint64(1 << uint(bitSize-1))
   181		if !neg && un >= cutoff {
   182			return int64(cutoff - 1), rangeError(fnParseInt, s0)
   183		}
   184		if neg && un > cutoff {
   185			return -int64(cutoff), rangeError(fnParseInt, s0)
   186		}
   187		n := int64(un)
   188		if neg {
   189			n = -n
   190		}
   191		return n, nil
   192	}
   193	
   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
   198	}
   199	

View as plain text