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

View as plain text