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 }