...
Run Format

Source file src/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(0) >> 63)
    35	
    36	// IntSize is the size in bits of an int or uint value.
    37	const IntSize = intSize
    38	
    39	const maxUint64 = (1<<64 - 1)
    40	
    41	// ParseUint is like ParseInt but for unsigned numbers.
    42	func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
    43		var cutoff, maxVal uint64
    44	
    45		if bitSize == 0 {
    46			bitSize = int(IntSize)
    47		}
    48	
    49		i := 0
    50		switch {
    51		case len(s) < 1:
    52			err = ErrSyntax
    53			goto Error
    54	
    55		case 2 <= base && base <= 36:
    56			// valid base; nothing to do
    57	
    58		case base == 0:
    59			// Look for octal, hex prefix.
    60			switch {
    61			case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
    62				if len(s) < 3 {
    63					err = ErrSyntax
    64					goto Error
    65				}
    66				base = 16
    67				i = 2
    68			case s[0] == '0':
    69				base = 8
    70				i = 1
    71			default:
    72				base = 10
    73			}
    74	
    75		default:
    76			err = errors.New("invalid base " + Itoa(base))
    77			goto Error
    78		}
    79	
    80		// Cutoff is the smallest number such that cutoff*base > maxUint64.
    81		// Use compile-time constants for common cases.
    82		switch base {
    83		case 10:
    84			cutoff = maxUint64/10 + 1
    85		case 16:
    86			cutoff = maxUint64/16 + 1
    87		default:
    88			cutoff = maxUint64/uint64(base) + 1
    89		}
    90	
    91		maxVal = 1<<uint(bitSize) - 1
    92	
    93		for ; i < len(s); i++ {
    94			var v byte
    95			d := s[i]
    96			switch {
    97			case '0' <= d && d <= '9':
    98				v = d - '0'
    99			case 'a' <= d && d <= 'z':
   100				v = d - 'a' + 10
   101			case 'A' <= d && d <= 'Z':
   102				v = d - 'A' + 10
   103			default:
   104				n = 0
   105				err = ErrSyntax
   106				goto Error
   107			}
   108			if v >= byte(base) {
   109				n = 0
   110				err = ErrSyntax
   111				goto Error
   112			}
   113	
   114			if n >= cutoff {
   115				// n*base overflows
   116				n = maxUint64
   117				err = ErrRange
   118				goto Error
   119			}
   120			n *= uint64(base)
   121	
   122			n1 := n + uint64(v)
   123			if n1 < n || n1 > maxVal {
   124				// n+v overflows
   125				n = maxUint64
   126				err = ErrRange
   127				goto Error
   128			}
   129			n = n1
   130		}
   131	
   132		return n, nil
   133	
   134	Error:
   135		return n, &NumError{"ParseUint", s, err}
   136	}
   137	
   138	// ParseInt interprets a string s in the given base (2 to 36) and
   139	// returns the corresponding value i.  If base == 0, the base is
   140	// implied by the string's prefix: base 16 for "0x", base 8 for
   141	// "0", and base 10 otherwise.
   142	//
   143	// The bitSize argument specifies the integer type
   144	// that the result must fit into.  Bit sizes 0, 8, 16, 32, and 64
   145	// correspond to int, int8, int16, int32, and int64.
   146	//
   147	// The errors that ParseInt returns have concrete type *NumError
   148	// and include err.Num = s.  If s is empty or contains invalid
   149	// digits, err.Err = ErrSyntax and the returned value is 0;
   150	// if the value corresponding to s cannot be represented by a
   151	// signed integer of the given size, err.Err = ErrRange and the
   152	// returned value is the maximum magnitude integer of the
   153	// appropriate bitSize and sign.
   154	func ParseInt(s string, base int, bitSize int) (i int64, err error) {
   155		const fnParseInt = "ParseInt"
   156	
   157		if bitSize == 0 {
   158			bitSize = int(IntSize)
   159		}
   160	
   161		// Empty string bad.
   162		if len(s) == 0 {
   163			return 0, syntaxError(fnParseInt, s)
   164		}
   165	
   166		// Pick off leading sign.
   167		s0 := s
   168		neg := false
   169		if s[0] == '+' {
   170			s = s[1:]
   171		} else if s[0] == '-' {
   172			neg = true
   173			s = s[1:]
   174		}
   175	
   176		// Convert unsigned and check range.
   177		var un uint64
   178		un, err = ParseUint(s, base, bitSize)
   179		if err != nil && err.(*NumError).Err != ErrRange {
   180			err.(*NumError).Func = fnParseInt
   181			err.(*NumError).Num = s0
   182			return 0, err
   183		}
   184		cutoff := uint64(1 << uint(bitSize-1))
   185		if !neg && un >= cutoff {
   186			return int64(cutoff - 1), rangeError(fnParseInt, s0)
   187		}
   188		if neg && un > cutoff {
   189			return -int64(cutoff), rangeError(fnParseInt, s0)
   190		}
   191		n := int64(un)
   192		if neg {
   193			n = -n
   194		}
   195		return n, nil
   196	}
   197	
   198	// Atoi is shorthand for ParseInt(s, 10, 0).
   199	func Atoi(s string) (i int, err error) {
   200		i64, err := ParseInt(s, 10, 0)
   201		return int(i64), err
   202	}
   203	

View as plain text