parseUintHex parses a hexadecimanl representation of a uint64 from b. The function is equivalent to calling strconv.ParseUint(string(b), 16, 64) but it prevents Go from making a memory allocation for converting a byte slice to a string (escape analysis fails due to the error returned by strconv.Par
(b []byte)
| 209 | // Because it only works with base 16 the function is also significantly faster |
| 210 | // than strconv.ParseUint. |
| 211 | func (d decoder) parseUintHex(b []byte) (uint64, []byte, error) { |
| 212 | const max = math.MaxUint64 |
| 213 | const lim = max / 0x10 |
| 214 | |
| 215 | var value uint64 |
| 216 | var count int |
| 217 | |
| 218 | if len(b) == 0 { |
| 219 | return 0, b, syntaxError(b, "cannot decode hexadecimal value from an empty input") |
| 220 | } |
| 221 | |
| 222 | parseLoop: |
| 223 | for i, c := range b { |
| 224 | var x uint64 |
| 225 | |
| 226 | switch { |
| 227 | case c >= '0' && c <= '9': |
| 228 | x = uint64(c - '0') |
| 229 | |
| 230 | case c >= 'A' && c <= 'F': |
| 231 | x = uint64(c-'A') + 0xA |
| 232 | |
| 233 | case c >= 'a' && c <= 'f': |
| 234 | x = uint64(c-'a') + 0xA |
| 235 | |
| 236 | default: |
| 237 | if i == 0 { |
| 238 | return 0, b, syntaxError(b, "expected hexadecimal digit but found '%c'", c) |
| 239 | } |
| 240 | break parseLoop |
| 241 | } |
| 242 | |
| 243 | if value > lim { |
| 244 | return 0, b, syntaxError(b, "hexadecimal value out of range") |
| 245 | } |
| 246 | |
| 247 | if value *= 0x10; value > (max - x) { |
| 248 | return 0, b, syntaxError(b, "hexadecimal value out of range") |
| 249 | } |
| 250 | |
| 251 | value += x |
| 252 | count++ |
| 253 | } |
| 254 | |
| 255 | return value, b[count:], nil |
| 256 | } |
| 257 | |
| 258 | func (d decoder) parseNull(b []byte) ([]byte, []byte, Kind, error) { |
| 259 | if hasNullPrefix(b) { |
no test coverage detected