You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

360 lines
7.3 KiB

package jx
import (
"bytes"
"io"
"math/big"
"strconv"
"github.com/go-faster/errors"
)
var pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000}
var floatDigits []int8
const invalidCharForNumber = int8(-1)
const endOfNumber = int8(-2)
const dotInNumber = int8(-3)
const maxFloat64 = 1<<63 - 1
func init() {
floatDigits = make([]int8, 256)
for i := 0; i < len(floatDigits); i++ {
floatDigits[i] = invalidCharForNumber
}
for i := int8('0'); i <= int8('9'); i++ {
floatDigits[i] = i - int8('0')
}
floatDigits[','] = endOfNumber
floatDigits[']'] = endOfNumber
floatDigits['}'] = endOfNumber
floatDigits[' '] = endOfNumber
floatDigits['\t'] = endOfNumber
floatDigits['\n'] = endOfNumber
floatDigits['.'] = dotInNumber
}
// BigFloat read big.Float
func (d *Decoder) BigFloat() (*big.Float, error) {
str, err := d.numberAppend(nil)
if err != nil {
return nil, errors.Wrap(err, "number")
}
prec := 64
if len(str) > prec {
prec = len(str)
}
val, _, err := big.ParseFloat(string(str), 10, uint(prec), big.ToZero)
if err != nil {
return nil, errors.Wrap(err, "float")
}
return val, nil
}
// BigInt read big.Int
func (d *Decoder) BigInt() (*big.Int, error) {
str, err := d.numberAppend(nil)
if err != nil {
return nil, errors.Wrap(err, "number")
}
v := big.NewInt(0)
var ok bool
if v, ok = v.SetString(string(str), 10); !ok {
return nil, errors.New("invalid")
}
return v, nil
}
// Float32 reads float32 value.
func (d *Decoder) Float32() (float32, error) {
c, err := d.more()
if err != nil {
return 0, errors.Wrap(err, "byte")
}
if c != '-' {
d.unread()
}
v, err := d.positiveFloat32()
if err != nil {
return 0, err
}
if c == '-' {
v *= -1
}
return v, nil
}
func (d *Decoder) positiveFloat32() (float32, error) {
i := d.head
// First char.
if i == d.tail {
return d.f32Slow()
}
c := d.buf[i]
i++
ind := floatDigits[c]
switch ind {
case invalidCharForNumber:
return d.f32Slow()
case endOfNumber:
return 0, errors.New("empty")
case dotInNumber:
return 0, errors.New("leading dot")
case 0:
if i == d.tail {
return d.f32Slow()
}
c = d.buf[i]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return 0, errors.New("leading zero")
}
}
value := uint64(ind)
// Chars before dot.
NonDecimalLoop:
for ; i < d.tail; i++ {
c = d.buf[i]
ind := floatDigits[c]
switch ind {
case invalidCharForNumber:
return d.f32Slow()
case endOfNumber:
d.head = i
return float32(value), nil
case dotInNumber:
break NonDecimalLoop
}
if value > uint64SafeToMultiple10 {
return d.f32Slow()
}
value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind;
}
// Chars after dot.
if c == '.' {
i++
decimalPlaces := 0
if i == d.tail {
return d.f32Slow()
}
for ; i < d.tail; i++ {
c = d.buf[i]
ind := floatDigits[c]
switch ind {
case endOfNumber:
if decimalPlaces > 0 && decimalPlaces < len(pow10) {
d.head = i
return float32(float64(value) / float64(pow10[decimalPlaces])), nil
}
// too many decimal places
return d.f32Slow()
case invalidCharForNumber, dotInNumber:
return d.f32Slow()
}
decimalPlaces++
if value > uint64SafeToMultiple10 {
return d.f32Slow()
}
value = (value << 3) + (value << 1) + uint64(ind)
}
}
return d.f32Slow()
}
func (d *Decoder) number() []byte {
start := d.head
buf := d.buf[d.head:d.tail]
for i, c := range buf {
switch c {
case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
continue
default:
// End of number.
d.head += i
return d.buf[start:d.head]
}
}
// Buffer is number within head:tail.
d.head = d.tail
return d.buf[start:d.tail]
}
func (d *Decoder) numberAppend(b []byte) ([]byte, error) {
for {
b = append(b, d.number()...)
if d.head != d.tail {
return b, nil
}
if err := d.read(); err != nil {
if err == io.EOF {
return b, nil
}
return b, err
}
}
}
const (
size32 = 32
size64 = 64
)
func (d *Decoder) f32Slow() (float32, error) {
v, err := d.floatSlow(size32)
if err != nil {
return 0, err
}
return float32(v), err
}
// Float64 read float64
func (d *Decoder) Float64() (float64, error) {
c, err := d.more()
if err != nil {
return 0, errors.Wrap(err, "byte")
}
switch c {
case '-':
v, err := d.positiveFloat64()
if err != nil {
return 0, err
}
return -v, err
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
d.unread()
return d.positiveFloat64()
default:
return 0, badToken(c)
}
}
func (d *Decoder) positiveFloat64() (float64, error) {
i := d.head
// First char.
if i == d.tail {
return d.float64Slow()
}
c := d.buf[i]
i++
ind := floatDigits[c]
switch ind {
case invalidCharForNumber:
return d.float64Slow()
case endOfNumber:
return 0, errors.New("empty")
case dotInNumber:
return 0, errors.New("leading dot")
case 0:
if i == d.tail {
return d.float64Slow()
}
c = d.buf[i]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return 0, errors.New("leading zero")
}
}
value := uint64(ind)
// Chars before dot.
NonDecimal:
for ; i < d.tail; i++ {
c = d.buf[i]
ind := floatDigits[c]
switch ind {
case invalidCharForNumber:
return d.float64Slow()
case endOfNumber:
d.head = i
return float64(value), nil
case dotInNumber:
break NonDecimal
}
if value > uint64SafeToMultiple10 {
return d.float64Slow()
}
value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind;
}
// chars after dot
if c == '.' {
i++
decimalPlaces := 0
if i == d.tail {
return d.float64Slow()
}
for ; i < d.tail; i++ {
c = d.buf[i]
ind := floatDigits[c]
switch ind {
case endOfNumber:
if decimalPlaces > 0 && decimalPlaces < len(pow10) {
d.head = i
return float64(value) / float64(pow10[decimalPlaces]), nil
}
// too many decimal places
return d.float64Slow()
case invalidCharForNumber, dotInNumber:
return d.float64Slow()
}
decimalPlaces++
// Not checking for uint64SafeToMultiple10 here because
// if condition is positive value multiplied by 10 is
// guaranteed to be bigger than maxFloat64.
value = (value << 3) + (value << 1) + uint64(ind)
if value > maxFloat64 {
return d.float64Slow()
}
}
}
return d.float64Slow()
}
func (d *Decoder) floatSlow(size int) (float64, error) {
var buf [32]byte
str, err := d.numberAppend(buf[:0])
if err != nil {
return 0, errors.Wrap(err, "number")
}
if err := validateFloat(str); err != nil {
return 0, errors.Wrap(err, "invalid")
}
val, err := strconv.ParseFloat(string(str), size)
if err != nil {
return 0, err
}
return val, nil
}
func (d *Decoder) float64Slow() (float64, error) { return d.floatSlow(size64) }
func validateFloat(str []byte) error {
// strconv.ParseFloat is not validating `1.` or `1.e1`
if len(str) == 0 {
return errors.New("empty")
}
if str[0] == '-' {
return errors.New("double minus")
}
if len(str) >= 2 && str[0] == '0' {
switch str[1] {
case 'e', 'E', '.':
default:
return errors.New("leading zero")
}
}
dotPos := bytes.IndexByte(str, '.')
if dotPos != -1 {
if dotPos == len(str)-1 {
return errors.New("dot as last char")
}
switch str[dotPos+1] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
default:
return errors.New("no digit after dot")
}
}
return nil
}