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; if the value corresponding
   146	// to s cannot be represented by a signed integer of the
   147	// given size, err.Err = ErrRange.
   148	func ParseInt(s string, base int, bitSize int) (i int64, err error) {
   149		const fnParseInt = "ParseInt"
   150	
   151		if bitSize == 0 {
   152			bitSize = int(IntSize)
   153		}
   154	
   155		// Empty string bad.
   156		if len(s) == 0 {
   157			return 0, syntaxError(fnParseInt, s)
   158		}
   159	
   160		// Pick off leading sign.
   161		s0 := s
   162		neg := false
   163		if s[0] == '+' {
   164			s = s[1:]
   165		} else if s[0] == '-' {
   166			neg = true
   167			s = s[1:]
   168		}
   169	
   170		// Convert unsigned and check range.
   171		var un uint64
   172		un, err = ParseUint(s, base, bitSize)
   173		if err != nil && err.(*NumError).Err != ErrRange {
   174			err.(*NumError).Func = fnParseInt
   175			err.(*NumError).Num = s0
   176			return 0, err
   177		}
   178		cutoff := uint64(1 << uint(bitSize-1))
   179		if !neg && un >= cutoff {
   180			return int64(cutoff - 1), rangeError(fnParseInt, s0)
   181		}
   182		if neg && un > cutoff {
   183			return -int64(cutoff), rangeError(fnParseInt, s0)
   184		}
   185		n := int64(un)
   186		if neg {
   187			n = -n
   188		}
   189		return n, nil
   190	}
   191	
   192	// Atoi is shorthand for ParseInt(s, 10, 0).
   193	func Atoi(s string) (i int, err error) {
   194		i64, err := ParseInt(s, 10, 0)
   195		return int(i64), err
   196	}

View as plain text