.github
alerting
client
config
controller
core
docs
example
jsonpath
k8s
k8stest
metric
pattern
security
static
storage
vendor
cloud.google.com
github.com
TwinProduction
beorn7
boltdb
cespare
davecgh
go-ping
gogo
golang
google
googleapis
gorilla
imdario
json-iterator
go
.codecov.yml
.gitignore
.travis.yml
Gopkg.lock
Gopkg.toml
LICENSE
README.md
adapter.go
any.go
any_array.go
any_bool.go
any_float.go
any_int32.go
any_int64.go
any_invalid.go
any_nil.go
any_number.go
any_object.go
any_str.go
any_uint32.go
any_uint64.go
build.sh
config.go
fuzzy_mode_convert_table.md
go.mod
go.sum
iter.go
iter_array.go
iter_float.go
iter_int.go
iter_object.go
iter_skip.go
iter_skip_sloppy.go
iter_skip_strict.go
iter_str.go
jsoniter.go
pool.go
reflect.go
reflect_array.go
reflect_dynamic.go
reflect_extension.go
reflect_json_number.go
reflect_json_raw_message.go
reflect_map.go
reflect_marshaler.go
reflect_native.go
reflect_optional.go
reflect_slice.go
reflect_struct_decoder.go
reflect_struct_encoder.go
stream.go
stream_float.go
stream_int.go
stream_str.go
test.sh
matttproud
miekg
modern-go
prometheus
spf13
golang.org
google.golang.org
gopkg.in
k8s.io
sigs.k8s.io
modules.txt
watchdog
.dockerignore
.gitattributes
.gitignore
Dockerfile
LICENSE.md
README.md
config.yaml
go.mod
go.sum
main.go
340 lines
7.4 KiB
Go
340 lines
7.4 KiB
Go
package jsoniter
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"math/big"
|
|
"strconv"
|
|
"strings"
|
|
"unsafe"
|
|
)
|
|
|
|
var floatDigits []int8
|
|
|
|
const invalidCharForNumber = int8(-1)
|
|
const endOfNumber = int8(-2)
|
|
const dotInNumber = int8(-3)
|
|
|
|
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
|
|
}
|
|
|
|
// ReadBigFloat read big.Float
|
|
func (iter *Iterator) ReadBigFloat() (ret *big.Float) {
|
|
str := iter.readNumberAsString()
|
|
if iter.Error != nil && iter.Error != io.EOF {
|
|
return nil
|
|
}
|
|
prec := 64
|
|
if len(str) > prec {
|
|
prec = len(str)
|
|
}
|
|
val, _, err := big.ParseFloat(str, 10, uint(prec), big.ToZero)
|
|
if err != nil {
|
|
iter.Error = err
|
|
return nil
|
|
}
|
|
return val
|
|
}
|
|
|
|
// ReadBigInt read big.Int
|
|
func (iter *Iterator) ReadBigInt() (ret *big.Int) {
|
|
str := iter.readNumberAsString()
|
|
if iter.Error != nil && iter.Error != io.EOF {
|
|
return nil
|
|
}
|
|
ret = big.NewInt(0)
|
|
var success bool
|
|
ret, success = ret.SetString(str, 10)
|
|
if !success {
|
|
iter.ReportError("ReadBigInt", "invalid big int")
|
|
return nil
|
|
}
|
|
return ret
|
|
}
|
|
|
|
//ReadFloat32 read float32
|
|
func (iter *Iterator) ReadFloat32() (ret float32) {
|
|
c := iter.nextToken()
|
|
if c == '-' {
|
|
return -iter.readPositiveFloat32()
|
|
}
|
|
iter.unreadByte()
|
|
return iter.readPositiveFloat32()
|
|
}
|
|
|
|
func (iter *Iterator) readPositiveFloat32() (ret float32) {
|
|
i := iter.head
|
|
// first char
|
|
if i == iter.tail {
|
|
return iter.readFloat32SlowPath()
|
|
}
|
|
c := iter.buf[i]
|
|
i++
|
|
ind := floatDigits[c]
|
|
switch ind {
|
|
case invalidCharForNumber:
|
|
return iter.readFloat32SlowPath()
|
|
case endOfNumber:
|
|
iter.ReportError("readFloat32", "empty number")
|
|
return
|
|
case dotInNumber:
|
|
iter.ReportError("readFloat32", "leading dot is invalid")
|
|
return
|
|
case 0:
|
|
if i == iter.tail {
|
|
return iter.readFloat32SlowPath()
|
|
}
|
|
c = iter.buf[i]
|
|
switch c {
|
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
iter.ReportError("readFloat32", "leading zero is invalid")
|
|
return
|
|
}
|
|
}
|
|
value := uint64(ind)
|
|
// chars before dot
|
|
non_decimal_loop:
|
|
for ; i < iter.tail; i++ {
|
|
c = iter.buf[i]
|
|
ind := floatDigits[c]
|
|
switch ind {
|
|
case invalidCharForNumber:
|
|
return iter.readFloat32SlowPath()
|
|
case endOfNumber:
|
|
iter.head = i
|
|
return float32(value)
|
|
case dotInNumber:
|
|
break non_decimal_loop
|
|
}
|
|
if value > uint64SafeToMultiple10 {
|
|
return iter.readFloat32SlowPath()
|
|
}
|
|
value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind;
|
|
}
|
|
// chars after dot
|
|
if c == '.' {
|
|
i++
|
|
decimalPlaces := 0
|
|
if i == iter.tail {
|
|
return iter.readFloat32SlowPath()
|
|
}
|
|
for ; i < iter.tail; i++ {
|
|
c = iter.buf[i]
|
|
ind := floatDigits[c]
|
|
switch ind {
|
|
case endOfNumber:
|
|
if decimalPlaces > 0 && decimalPlaces < len(pow10) {
|
|
iter.head = i
|
|
return float32(float64(value) / float64(pow10[decimalPlaces]))
|
|
}
|
|
// too many decimal places
|
|
return iter.readFloat32SlowPath()
|
|
case invalidCharForNumber, dotInNumber:
|
|
return iter.readFloat32SlowPath()
|
|
}
|
|
decimalPlaces++
|
|
if value > uint64SafeToMultiple10 {
|
|
return iter.readFloat32SlowPath()
|
|
}
|
|
value = (value << 3) + (value << 1) + uint64(ind)
|
|
}
|
|
}
|
|
return iter.readFloat32SlowPath()
|
|
}
|
|
|
|
func (iter *Iterator) readNumberAsString() (ret string) {
|
|
strBuf := [16]byte{}
|
|
str := strBuf[0:0]
|
|
load_loop:
|
|
for {
|
|
for i := iter.head; i < iter.tail; i++ {
|
|
c := iter.buf[i]
|
|
switch c {
|
|
case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
str = append(str, c)
|
|
continue
|
|
default:
|
|
iter.head = i
|
|
break load_loop
|
|
}
|
|
}
|
|
if !iter.loadMore() {
|
|
break
|
|
}
|
|
}
|
|
if iter.Error != nil && iter.Error != io.EOF {
|
|
return
|
|
}
|
|
if len(str) == 0 {
|
|
iter.ReportError("readNumberAsString", "invalid number")
|
|
}
|
|
return *(*string)(unsafe.Pointer(&str))
|
|
}
|
|
|
|
func (iter *Iterator) readFloat32SlowPath() (ret float32) {
|
|
str := iter.readNumberAsString()
|
|
if iter.Error != nil && iter.Error != io.EOF {
|
|
return
|
|
}
|
|
errMsg := validateFloat(str)
|
|
if errMsg != "" {
|
|
iter.ReportError("readFloat32SlowPath", errMsg)
|
|
return
|
|
}
|
|
val, err := strconv.ParseFloat(str, 32)
|
|
if err != nil {
|
|
iter.Error = err
|
|
return
|
|
}
|
|
return float32(val)
|
|
}
|
|
|
|
// ReadFloat64 read float64
|
|
func (iter *Iterator) ReadFloat64() (ret float64) {
|
|
c := iter.nextToken()
|
|
if c == '-' {
|
|
return -iter.readPositiveFloat64()
|
|
}
|
|
iter.unreadByte()
|
|
return iter.readPositiveFloat64()
|
|
}
|
|
|
|
func (iter *Iterator) readPositiveFloat64() (ret float64) {
|
|
i := iter.head
|
|
// first char
|
|
if i == iter.tail {
|
|
return iter.readFloat64SlowPath()
|
|
}
|
|
c := iter.buf[i]
|
|
i++
|
|
ind := floatDigits[c]
|
|
switch ind {
|
|
case invalidCharForNumber:
|
|
return iter.readFloat64SlowPath()
|
|
case endOfNumber:
|
|
iter.ReportError("readFloat64", "empty number")
|
|
return
|
|
case dotInNumber:
|
|
iter.ReportError("readFloat64", "leading dot is invalid")
|
|
return
|
|
case 0:
|
|
if i == iter.tail {
|
|
return iter.readFloat64SlowPath()
|
|
}
|
|
c = iter.buf[i]
|
|
switch c {
|
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
iter.ReportError("readFloat64", "leading zero is invalid")
|
|
return
|
|
}
|
|
}
|
|
value := uint64(ind)
|
|
// chars before dot
|
|
non_decimal_loop:
|
|
for ; i < iter.tail; i++ {
|
|
c = iter.buf[i]
|
|
ind := floatDigits[c]
|
|
switch ind {
|
|
case invalidCharForNumber:
|
|
return iter.readFloat64SlowPath()
|
|
case endOfNumber:
|
|
iter.head = i
|
|
return float64(value)
|
|
case dotInNumber:
|
|
break non_decimal_loop
|
|
}
|
|
if value > uint64SafeToMultiple10 {
|
|
return iter.readFloat64SlowPath()
|
|
}
|
|
value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind;
|
|
}
|
|
// chars after dot
|
|
if c == '.' {
|
|
i++
|
|
decimalPlaces := 0
|
|
if i == iter.tail {
|
|
return iter.readFloat64SlowPath()
|
|
}
|
|
for ; i < iter.tail; i++ {
|
|
c = iter.buf[i]
|
|
ind := floatDigits[c]
|
|
switch ind {
|
|
case endOfNumber:
|
|
if decimalPlaces > 0 && decimalPlaces < len(pow10) {
|
|
iter.head = i
|
|
return float64(value) / float64(pow10[decimalPlaces])
|
|
}
|
|
// too many decimal places
|
|
return iter.readFloat64SlowPath()
|
|
case invalidCharForNumber, dotInNumber:
|
|
return iter.readFloat64SlowPath()
|
|
}
|
|
decimalPlaces++
|
|
if value > uint64SafeToMultiple10 {
|
|
return iter.readFloat64SlowPath()
|
|
}
|
|
value = (value << 3) + (value << 1) + uint64(ind)
|
|
}
|
|
}
|
|
return iter.readFloat64SlowPath()
|
|
}
|
|
|
|
func (iter *Iterator) readFloat64SlowPath() (ret float64) {
|
|
str := iter.readNumberAsString()
|
|
if iter.Error != nil && iter.Error != io.EOF {
|
|
return
|
|
}
|
|
errMsg := validateFloat(str)
|
|
if errMsg != "" {
|
|
iter.ReportError("readFloat64SlowPath", errMsg)
|
|
return
|
|
}
|
|
val, err := strconv.ParseFloat(str, 64)
|
|
if err != nil {
|
|
iter.Error = err
|
|
return
|
|
}
|
|
return val
|
|
}
|
|
|
|
func validateFloat(str string) string {
|
|
// strconv.ParseFloat is not validating `1.` or `1.e1`
|
|
if len(str) == 0 {
|
|
return "empty number"
|
|
}
|
|
if str[0] == '-' {
|
|
return "-- is not valid"
|
|
}
|
|
dotPos := strings.IndexByte(str, '.')
|
|
if dotPos != -1 {
|
|
if dotPos == len(str)-1 {
|
|
return "dot can not be last character"
|
|
}
|
|
switch str[dotPos+1] {
|
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
default:
|
|
return "missing digit after dot"
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// ReadNumber read json.Number
|
|
func (iter *Iterator) ReadNumber() (ret json.Number) {
|
|
return json.Number(iter.readNumberAsString())
|
|
}
|