github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/internal/strconv/strconv.go (about)

     1  package strconv
     2  
     3  import (
     4  	"math"
     5  	"strconv"
     6  	"strings"
     7  	"unicode/utf8"
     8  )
     9  
    10  var (
    11  	ErrSyntax = strconv.ErrSyntax
    12  	ErrRange  = strconv.ErrRange
    13  )
    14  
    15  func Atoi(s string) (i int, err error) {
    16  	i64, err := ParseInt(s)
    17  	return int(i64), err
    18  }
    19  
    20  func Itoa(i int) string {
    21  	return FormatInt(int64(i), 10)
    22  }
    23  
    24  func AppendInt(dst []byte, i int64, base int) []byte {
    25  	return strconv.AppendInt(dst, i, base)
    26  }
    27  
    28  func FormatInt(i int64, base int) string {
    29  	return strconv.FormatInt(i, base)
    30  }
    31  
    32  func FormatUint(u uint64, base int) string {
    33  	return strconv.FormatUint(u, base)
    34  }
    35  
    36  func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
    37  	s := strconv.FormatFloat(f, fmt, prec, bitSize)
    38  
    39  	switch s {
    40  	case "NaN":
    41  		return "nan"
    42  	case "-Inf":
    43  		return "-inf"
    44  	case "+Inf":
    45  		return "inf"
    46  	}
    47  
    48  	return s
    49  }
    50  
    51  func ParseUint(s string) (uint64, error) {
    52  	if len(s) == 0 {
    53  		return 0, ErrSyntax
    54  	}
    55  
    56  	if s[0] == '0' && len(s) != 1 && (s[1] == 'x' || s[1] == 'X') {
    57  		u, err := strconv.ParseUint(s[2:], 16, 64)
    58  		return u, unwrap(err)
    59  	}
    60  
    61  	i, err := strconv.ParseUint(s, 10, 64)
    62  	if err != nil {
    63  		f, err := strconv.ParseFloat(s, 64)
    64  		return uint64(f), unwrap(err)
    65  	}
    66  
    67  	return i, nil
    68  }
    69  
    70  func ParseInt(s string) (int64, error) {
    71  	if len(s) == 0 {
    72  		return 0, ErrSyntax
    73  	}
    74  
    75  	t := s
    76  
    77  	var neg bool
    78  
    79  	switch s[0] {
    80  	case '-':
    81  		neg = true
    82  		t = t[1:]
    83  	case '+':
    84  		t = t[1:]
    85  	}
    86  
    87  	var i int64
    88  	var err error
    89  
    90  	if len(t) > 1 && t[0] == '0' && (t[1] == 'x' || t[1] == 'X') {
    91  		var u uint64
    92  		u, err = strconv.ParseUint(t[2:], 16, 64)
    93  		i = int64(u)
    94  		if neg {
    95  			i = -i
    96  		}
    97  	} else {
    98  		i, err = strconv.ParseInt(s, 10, 64)
    99  	}
   100  
   101  	return i, unwrap(err)
   102  }
   103  
   104  func ParseFloat(s string) (float64, error) {
   105  	if len(s) == 0 {
   106  		return 0, ErrSyntax
   107  	}
   108  
   109  	t := s
   110  
   111  	var neg bool
   112  
   113  	switch s[0] {
   114  	case '-':
   115  		neg = true
   116  		t = t[1:]
   117  	case '+':
   118  		t = t[1:]
   119  	}
   120  
   121  	var f float64
   122  	var err error
   123  
   124  	if len(t) > 1 && t[0] == '0' && (t[1] == 'x' || t[1] == 'X') {
   125  		f, err = parseHexFloat(t[2:])
   126  		if neg {
   127  			f = math.Copysign(f, -1)
   128  		}
   129  	} else {
   130  		if len(t) > 0 && !(('0' <= t[0] && t[0] <= '9') || t[0] == '.') { // drop special cases. e.g "inf", "nan", ...
   131  			err = ErrSyntax
   132  		} else {
   133  			f, err = strconv.ParseFloat(s, 64)
   134  		}
   135  	}
   136  
   137  	return f, unwrap(err)
   138  }
   139  
   140  func parseHexFloat(s string) (float64, error) {
   141  	if len(s) == 0 {
   142  		return 0, ErrSyntax
   143  	}
   144  
   145  	var integer string
   146  	var fraction string
   147  	var exponent string
   148  
   149  	if j := strings.IndexRune(s, '.'); j != -1 {
   150  		integer = s[:j]
   151  		s = s[j+1:]
   152  		if k := strings.IndexAny(s, "pP"); k != -1 {
   153  			fraction = s[:k]
   154  			exponent = s[k+1:]
   155  			if exponent == "" {
   156  				return 0, ErrSyntax
   157  			}
   158  		} else {
   159  			fraction = s
   160  		}
   161  	} else {
   162  		if k := strings.IndexAny(s, "pP"); k != -1 {
   163  			integer = s[:k]
   164  			exponent = s[k+1:]
   165  			if exponent == "" {
   166  				return 0, ErrSyntax
   167  			}
   168  		} else {
   169  			integer = s
   170  		}
   171  	}
   172  
   173  	var f float64
   174  
   175  	if integer != "" {
   176  		i, err := strconv.ParseInt(integer, 16, 64)
   177  		if err != nil {
   178  			return 0, unwrap(err)
   179  		}
   180  
   181  		f = float64(i)
   182  	}
   183  
   184  	if fraction != "" {
   185  		coef := 16.0
   186  
   187  		var x int
   188  		for _, r := range fraction {
   189  			if r >= utf8.RuneSelf {
   190  				return 0, ErrSyntax
   191  			}
   192  			x = digitVal(byte(r))
   193  			if x == 16 {
   194  				return 0, ErrSyntax
   195  			}
   196  
   197  			// do nothing
   198  			if x == '0' {
   199  				coef *= 16
   200  				continue
   201  			}
   202  
   203  			f += float64(x) / coef
   204  
   205  			coef *= 16
   206  		}
   207  	}
   208  
   209  	if exponent != "" {
   210  		e, err := strconv.ParseInt(exponent, 10, 64)
   211  		if err != nil {
   212  			return 0, unwrap(err)
   213  		}
   214  
   215  		f = f * math.Pow(2, float64(e))
   216  	}
   217  
   218  	return f, nil
   219  }
   220  
   221  func digitVal(c byte) int {
   222  	switch {
   223  	case uint(c)-'0' < 10:
   224  		return int(c - '0')
   225  	case uint(c)-'a' < 6:
   226  		return int(c - 'a' + 10)
   227  	case uint(c)-'A' < 6:
   228  		return int(c - 'A' + 10)
   229  	}
   230  
   231  	return 16
   232  }
   233  
   234  func unwrap(err error) error {
   235  	if err == nil {
   236  		return nil
   237  	}
   238  
   239  	if nerr, ok := err.(*strconv.NumError); ok {
   240  		return nerr.Err
   241  	}
   242  
   243  	return err
   244  }