mirror of
https://github.com/ii64/sonic.git
synced 2026-06-20 16:45:22 +08:00
opt: skip number in json.Number parsing (#209)
* opt: skip number in json.Number parsing * fix: generic use skip_number * test: add json.Number decoding benchmarks Co-authored-by: liuqiang <liuqiang.06@bytedance.com> Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com>
This commit is contained in:
parent
fe2497d01e
commit
57989f38ba
22 changed files with 1570 additions and 1153 deletions
|
|
@ -581,15 +581,6 @@ func (self *_Assembler) check_err() {
|
|||
self.Sjmp("JS" , _LB_parsing_error_v) // JNE _parsing_error_v
|
||||
}
|
||||
|
||||
func (self *_Assembler) check_err_num() {
|
||||
self.Emit("MOVQ" , _VAR_st_Vt, _AX) // MOVQ st.Vt, AX
|
||||
self.Emit("TESTQ", _AX, _AX) // CMPQ AX, ${native.V_STRING}
|
||||
self.Sjmp("JNS" , "check_err_end_{n}")
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(-int64(types.ERR_FLOAT_INFINITY)))
|
||||
self.Sjmp("JNE" , _LB_parsing_error_v)
|
||||
self.Link("check_err_end_{n}")
|
||||
}
|
||||
|
||||
func (self *_Assembler) check_eof(d int64) {
|
||||
if d == 1 {
|
||||
self.Emit("CMPQ", _IC, _IL) // CMPQ IC, IL
|
||||
|
|
@ -942,6 +933,7 @@ func (self *_Assembler) mapassign_utext(t reflect.Type, addressable bool) {
|
|||
|
||||
var (
|
||||
_F_skip_one = jit.Imm(int64(native.S_skip_one))
|
||||
_F_skip_number = jit.Imm(int64(native.S_skip_number))
|
||||
)
|
||||
|
||||
func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool) {
|
||||
|
|
@ -1176,13 +1168,21 @@ func (self *_Assembler) _asm_OP_bool(_ *_Instr) {
|
|||
func (self *_Assembler) _asm_OP_num(_ *_Instr) {
|
||||
self.Emit("MOVQ", jit.Imm(0), _VAR_fl)
|
||||
self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"'))
|
||||
self.Sjmp("JNE", "_parse_number_{n}")
|
||||
self.Sjmp("JNE", "_skip_number_{n}")
|
||||
self.Emit("MOVQ", jit.Imm(1), _VAR_fl)
|
||||
self.Emit("ADDQ", jit.Imm(1), _IC)
|
||||
self.Link("_parse_number_{n}")
|
||||
self.call_vf(_F_vnumber) // call vnumber
|
||||
self.check_err_num()
|
||||
self.slice_from(_VAR_st_Ep, 0) // SLICE st.Ep, $0
|
||||
self.Link("_skip_number_{n}")
|
||||
|
||||
/* call skip_number */
|
||||
self.Emit("LEAQ", _ARG_s, _DI) // LEAQ s<>+0(FP), DI
|
||||
self.Emit("MOVQ", _IC, _ARG_ic) // MOVQ IC, ic<>+16(FP)
|
||||
self.Emit("LEAQ", _ARG_ic, _SI) // LEAQ ic<>+16(FP), SI
|
||||
self.call(_F_skip_number) // CALL _F_skip_number
|
||||
self.Emit("MOVQ", _ARG_ic, _IC) // MOVQ ic<>+16(FP), IC
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v
|
||||
|
||||
self.slice_from_r(_AX, 0)
|
||||
self.Emit("BTQ", jit.Imm(_F_copy_string), _ARG_fv)
|
||||
self.Sjmp("JNC", "_num_write_{n}")
|
||||
self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9
|
||||
|
|
|
|||
|
|
@ -591,15 +591,6 @@ func (self *_Assembler) check_err() {
|
|||
self.Sjmp("JS" , _LB_parsing_error_v) // JNE _parsing_error_v
|
||||
}
|
||||
|
||||
func (self *_Assembler) check_err_num() {
|
||||
self.Emit("MOVQ" , _VAR_st_Vt, _AX) // MOVQ st.Vt, AX
|
||||
self.Emit("TESTQ", _AX, _AX) // CMPQ AX, ${native.V_STRING}
|
||||
self.Sjmp("JNS" , "check_err_end_{n}")
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(-int64(types.ERR_FLOAT_INFINITY)))
|
||||
self.Sjmp("JNE" , _LB_parsing_error_v)
|
||||
self.Link("check_err_end_{n}")
|
||||
}
|
||||
|
||||
func (self *_Assembler) check_eof(d int64) {
|
||||
if d == 1 {
|
||||
self.Emit("CMPQ", _IC, _IL) // CMPQ IC, IL
|
||||
|
|
@ -943,6 +934,7 @@ func (self *_Assembler) mapassign_utext(t reflect.Type, addressable bool) {
|
|||
|
||||
var (
|
||||
_F_skip_one = jit.Imm(int64(native.S_skip_one))
|
||||
_F_skip_number = jit.Imm(int64(native.S_skip_number))
|
||||
)
|
||||
|
||||
func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool) {
|
||||
|
|
@ -1173,13 +1165,21 @@ func (self *_Assembler) _asm_OP_bool(_ *_Instr) {
|
|||
func (self *_Assembler) _asm_OP_num(_ *_Instr) {
|
||||
self.Emit("MOVQ", jit.Imm(0), _VAR_fl)
|
||||
self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"'))
|
||||
self.Sjmp("JNE", "_parse_number_{n}")
|
||||
self.Sjmp("JNE", "_skip_number_{n}")
|
||||
self.Emit("MOVQ", jit.Imm(1), _VAR_fl)
|
||||
self.Emit("ADDQ", jit.Imm(1), _IC)
|
||||
self.Link("_parse_number_{n}")
|
||||
self.call_vf(_F_vnumber)
|
||||
self.check_err_num()
|
||||
self.slice_from(_VAR_st_Ep, 0) // SLICE st.Ep, $0
|
||||
self.Link("_skip_number_{n}")
|
||||
|
||||
/* call skip_number */
|
||||
self.Emit("LEAQ", _ARG_s, _DI) // LEAQ s<>+0(FP), DI
|
||||
self.Emit("MOVQ", _IC, _ARG_ic) // MOVQ IC, ic<>+16(FP)
|
||||
self.Emit("LEAQ", _ARG_ic, _SI) // LEAQ ic<>+16(FP), SI
|
||||
self.callc(_F_skip_number) // CALL _F_skip_number
|
||||
self.Emit("MOVQ", _ARG_ic, _IC) // MOVQ ic<>+16(FP), IC
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v
|
||||
|
||||
self.slice_from_r(_AX, 0)
|
||||
self.Emit("BTQ", jit.Imm(_F_copy_string), _ARG_fv)
|
||||
self.Sjmp("JNC", "_num_write_{n}")
|
||||
self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ const (
|
|||
_F_disable_urc
|
||||
_F_disable_unknown
|
||||
_F_copy_string
|
||||
|
||||
_F_allow_control = 31
|
||||
)
|
||||
|
||||
// Decoder is the decoder context object
|
||||
|
|
|
|||
|
|
@ -266,21 +266,16 @@ func (self *_ValueDecoder) compile() {
|
|||
self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI
|
||||
self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX
|
||||
self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
|
||||
self.Emit("MOVL", jit.Imm(1), _R8) // MOVL $1, R8
|
||||
self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8
|
||||
self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8
|
||||
self.call(_F_value) // CALL value
|
||||
self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
|
||||
|
||||
/* check for errors */
|
||||
self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , "_parsing_error")
|
||||
self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype
|
||||
self.Sjmp("JNS" , "_not_sign") // JNS
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(-int64(types.ERR_FLOAT_INFINITY)))
|
||||
self.Sjmp("JNE" , "_parsing_error")
|
||||
self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
|
||||
self.Sjmp("JNC" , "_parsing_error")
|
||||
self.Emit("MOVQ" , jit.Imm(int64(types.V_DOUBLE)), _AX)
|
||||
self.Link("_not_sign")
|
||||
self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max
|
||||
self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype
|
||||
|
||||
|
|
|
|||
|
|
@ -281,21 +281,16 @@ func (self *_ValueDecoder) compile() {
|
|||
self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI
|
||||
self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX
|
||||
self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
|
||||
self.Emit("MOVL", jit.Imm(1), _R8) // MOVL $1, R8
|
||||
self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8
|
||||
self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8
|
||||
self.callc(_F_value) // CALL value
|
||||
self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
|
||||
|
||||
/* check for errors */
|
||||
self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , "_parsing_error")
|
||||
self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype
|
||||
self.Sjmp("JNS" , "_not_sign") // JNS
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(-int64(types.ERR_FLOAT_INFINITY)))
|
||||
self.Sjmp("JNE" , "_parsing_error")
|
||||
self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
|
||||
self.Sjmp("JNC" , "_parsing_error")
|
||||
self.Emit("MOVQ" , jit.Imm(int64(types.V_DOUBLE)), _AX)
|
||||
self.Link("_not_sign")
|
||||
self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max
|
||||
self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,11 @@ func __skip_array(s *string, p *int, m *types.StateMachine) (ret int)
|
|||
//goland:noinspection GoUnusedParameter
|
||||
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
|
||||
|
||||
//go:nosplit
|
||||
//go:noescape
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func __skip_number(s *string, p *int) (ret int)
|
||||
|
||||
//go:nosplit
|
||||
//go:noescape
|
||||
//goland:noinspection GoUnusedParameter
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -565,3 +565,11 @@ func TestNative_SkipObject(t *testing.T) {
|
|||
__skip_object(&s, &p, &types.StateMachine{})
|
||||
assert.Equal(t, p, 15)
|
||||
}
|
||||
|
||||
func TestNative_SkipNumber(t *testing.T) {
|
||||
p := 0
|
||||
s := `-1.23e+12`
|
||||
q := __skip_number(&s, &p)
|
||||
assert.Equal(t, 9, p)
|
||||
assert.Equal(t, 0, q)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,4 +42,5 @@ var (
|
|||
S_skip_one = _subr__skip_one
|
||||
S_skip_array = _subr__skip_array
|
||||
S_skip_object = _subr__skip_object
|
||||
S_skip_number = _subr__skip_number
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,17 +15,18 @@ var (
|
|||
_subr__lspace = __native_entry__() + 301
|
||||
_subr__lzero = __native_entry__() + 13
|
||||
_subr__quote = __native_entry__() + 4955
|
||||
_subr__skip_array = __native_entry__() + 17370
|
||||
_subr__skip_object = __native_entry__() + 17407
|
||||
_subr__skip_one = __native_entry__() + 15518
|
||||
_subr__skip_array = __native_entry__() + 17551
|
||||
_subr__skip_number = __native_entry__() + 20669
|
||||
_subr__skip_object = __native_entry__() + 17588
|
||||
_subr__skip_one = __native_entry__() + 15699
|
||||
_subr__u64toa = __native_entry__() + 3735
|
||||
_subr__unquote = __native_entry__() + 6005
|
||||
_subr__validate_one = __native_entry__() + 20488
|
||||
_subr__validate_one = __native_entry__() + 20786
|
||||
_subr__value = __native_entry__() + 10880
|
||||
_subr__vnumber = __native_entry__() + 13676
|
||||
_subr__vsigned = __native_entry__() + 14990
|
||||
_subr__vstring = __native_entry__() + 12641
|
||||
_subr__vunsigned = __native_entry__() + 15249
|
||||
_subr__vnumber = __native_entry__() + 13857
|
||||
_subr__vsigned = __native_entry__() + 15171
|
||||
_subr__vstring = __native_entry__() + 12822
|
||||
_subr__vunsigned = __native_entry__() + 15430
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -36,12 +37,13 @@ const (
|
|||
_stack__lzero = 8
|
||||
_stack__quote = 80
|
||||
_stack__skip_array = 160
|
||||
_stack__skip_number = 96
|
||||
_stack__skip_object = 160
|
||||
_stack__skip_one = 160
|
||||
_stack__u64toa = 8
|
||||
_stack__unquote = 88
|
||||
_stack__validate_one = 160
|
||||
_stack__value = 400
|
||||
_stack__value = 416
|
||||
_stack__vnumber = 312
|
||||
_stack__vsigned = 16
|
||||
_stack__vstring = 128
|
||||
|
|
@ -56,6 +58,7 @@ var (
|
|||
_ = _subr__lzero
|
||||
_ = _subr__quote
|
||||
_ = _subr__skip_array
|
||||
_ = _subr__skip_number
|
||||
_ = _subr__skip_object
|
||||
_ = _subr__skip_one
|
||||
_ = _subr__u64toa
|
||||
|
|
@ -76,6 +79,7 @@ const (
|
|||
_ = _stack__lzero
|
||||
_ = _stack__quote
|
||||
_ = _stack__skip_array
|
||||
_ = _stack__skip_number
|
||||
_ = _stack__skip_object
|
||||
_ = _stack__skip_one
|
||||
_ = _stack__u64toa
|
||||
|
|
|
|||
|
|
@ -104,6 +104,11 @@ func __skip_array(s *string, p *int, m *types.StateMachine) (ret int)
|
|||
//goland:noinspection GoUnusedParameter
|
||||
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
|
||||
|
||||
//go:nosplit
|
||||
//go:noescape
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func __skip_number(s *string, p *int) (ret int)
|
||||
|
||||
//go:nosplit
|
||||
//go:noescape
|
||||
//goland:noinspection GoUnusedParameter
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -565,3 +565,11 @@ func TestNative_SkipObject(t *testing.T) {
|
|||
__skip_object(&s, &p, &types.StateMachine{})
|
||||
assert.Equal(t, p, 15)
|
||||
}
|
||||
|
||||
func TestNative_SkipNumber(t *testing.T) {
|
||||
p := 0
|
||||
s := `-1.23e+12`
|
||||
q := __skip_number(&s, &p)
|
||||
assert.Equal(t, 9, p)
|
||||
assert.Equal(t, 0, q)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,4 +42,5 @@ var (
|
|||
S_skip_one = _subr__skip_one
|
||||
S_skip_array = _subr__skip_array
|
||||
S_skip_object = _subr__skip_object
|
||||
S_skip_number = _subr__skip_number
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,17 +15,18 @@ var (
|
|||
_subr__lspace = __native_entry__() + 429
|
||||
_subr__lzero = __native_entry__() + 13
|
||||
_subr__quote = __native_entry__() + 5328
|
||||
_subr__skip_array = __native_entry__() + 21375
|
||||
_subr__skip_object = __native_entry__() + 21412
|
||||
_subr__skip_one = __native_entry__() + 18275
|
||||
_subr__skip_array = __native_entry__() + 21558
|
||||
_subr__skip_number = __native_entry__() + 25206
|
||||
_subr__skip_object = __native_entry__() + 21595
|
||||
_subr__skip_one = __native_entry__() + 18458
|
||||
_subr__u64toa = __native_entry__() + 4008
|
||||
_subr__unquote = __native_entry__() + 7080
|
||||
_subr__validate_one = __native_entry__() + 25023
|
||||
_subr__validate_one = __native_entry__() + 25323
|
||||
_subr__value = __native_entry__() + 13781
|
||||
_subr__vnumber = __native_entry__() + 16433
|
||||
_subr__vsigned = __native_entry__() + 17747
|
||||
_subr__vstring = __native_entry__() + 15556
|
||||
_subr__vunsigned = __native_entry__() + 18006
|
||||
_subr__vnumber = __native_entry__() + 16616
|
||||
_subr__vsigned = __native_entry__() + 17930
|
||||
_subr__vstring = __native_entry__() + 15739
|
||||
_subr__vunsigned = __native_entry__() + 18189
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -36,12 +37,13 @@ const (
|
|||
_stack__lzero = 8
|
||||
_stack__quote = 64
|
||||
_stack__skip_array = 136
|
||||
_stack__skip_number = 96
|
||||
_stack__skip_object = 136
|
||||
_stack__skip_one = 136
|
||||
_stack__u64toa = 8
|
||||
_stack__unquote = 72
|
||||
_stack__validate_one = 136
|
||||
_stack__value = 392
|
||||
_stack__value = 408
|
||||
_stack__vnumber = 312
|
||||
_stack__vsigned = 16
|
||||
_stack__vstring = 112
|
||||
|
|
@ -56,6 +58,7 @@ var (
|
|||
_ = _subr__lzero
|
||||
_ = _subr__quote
|
||||
_ = _subr__skip_array
|
||||
_ = _subr__skip_number
|
||||
_ = _subr__skip_object
|
||||
_ = _subr__skip_one
|
||||
_ = _subr__u64toa
|
||||
|
|
@ -76,6 +79,7 @@ const (
|
|||
_ = _stack__lzero
|
||||
_ = _stack__quote
|
||||
_ = _stack__skip_array
|
||||
_ = _stack__skip_number
|
||||
_ = _stack__skip_object
|
||||
_ = _stack__skip_one
|
||||
_ = _stack__u64toa
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ var (
|
|||
S_skip_one uintptr
|
||||
S_skip_array uintptr
|
||||
S_skip_object uintptr
|
||||
S_skip_number uintptr
|
||||
)
|
||||
|
||||
//go:nosplit
|
||||
|
|
@ -113,6 +114,7 @@ func useAVX() {
|
|||
S_skip_one = avx.S_skip_one
|
||||
S_skip_array = avx.S_skip_array
|
||||
S_skip_object = avx.S_skip_object
|
||||
S_skip_number = avx.S_skip_number
|
||||
}
|
||||
|
||||
func useAVX2() {
|
||||
|
|
@ -130,6 +132,7 @@ func useAVX2() {
|
|||
S_skip_one = avx2.S_skip_one
|
||||
S_skip_array = avx2.S_skip_array
|
||||
S_skip_object = avx2.S_skip_object
|
||||
S_skip_number = avx2.S_skip_number
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
|
|||
|
|
@ -102,6 +102,11 @@ func __skip_array(s *string, p *int, m *types.StateMachine) (ret int)
|
|||
//goland:noinspection GoUnusedParameter
|
||||
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
|
||||
|
||||
//go:nosplit
|
||||
//go:noescape
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func __skip_number(s *string, p *int) (ret int)
|
||||
|
||||
//go:nosplit
|
||||
//go:noescape
|
||||
//goland:noinspection GoUnusedParameter
|
||||
|
|
|
|||
|
|
@ -563,3 +563,11 @@ func TestNative_SkipObject(t *testing.T) {
|
|||
__skip_object(&s, &p, &types.StateMachine{})
|
||||
assert.Equal(t, p, 15)
|
||||
}
|
||||
|
||||
func TestNative_SkipNumber(t *testing.T) {
|
||||
p := 0
|
||||
s := `-1.23e+12`
|
||||
q := __skip_number(&s, &p)
|
||||
assert.Equal(t, 9, p)
|
||||
assert.Equal(t, 0, q)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,4 +40,5 @@ var (
|
|||
S_skip_one = _subr__skip_one
|
||||
S_skip_array = _subr__skip_array
|
||||
S_skip_object = _subr__skip_object
|
||||
S_skip_number = _subr__skip_number
|
||||
)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
var issue_19x_idata = "\"" + strings.Repeat("9", 1000) + "\""
|
||||
var issue_19x_fdata = "\"" + strings.Repeat("9", 100) + "." + strings.Repeat("9", 1000) + "\""
|
||||
var issue_19x_ndata = strings.Repeat("9", 1000)
|
||||
var issue_19x_invalid = strings.Repeat("9", 100) + "abc99"
|
||||
|
||||
func TestDecodeLongStringToJsonNumber(t *testing.T) {
|
||||
var objs, obje json.Number
|
||||
|
|
@ -45,6 +46,13 @@ func TestDecodeLongStringToJsonNumber(t *testing.T) {
|
|||
require.Equal(t, erre, errs)
|
||||
require.Equal(t, fobje, fobjs)
|
||||
|
||||
var objs2, obje2 json.Number
|
||||
errs = sonic.UnmarshalString(issue_19x_invalid, &objs2)
|
||||
erre = json.Unmarshal([]byte(issue_19x_invalid), &obje2)
|
||||
require.NotNil(t, erre)
|
||||
require.NotNil(t, errs)
|
||||
|
||||
|
||||
var iobjs, iobje interface{}
|
||||
dc := decoder.NewDecoder(issue_19x_ndata)
|
||||
dc.UseNumber()
|
||||
|
|
@ -54,4 +62,37 @@ func TestDecodeLongStringToJsonNumber(t *testing.T) {
|
|||
erre = r.Decode(&iobje)
|
||||
require.Equal(t, erre, errs)
|
||||
require.Equal(t, iobje, iobjs)
|
||||
|
||||
var iobjs2, iobje2 interface{}
|
||||
dc = decoder.NewDecoder(issue_19x_invalid)
|
||||
dc.UseNumber()
|
||||
errs = dc.Decode(&iobjs2)
|
||||
r = json.NewDecoder(bytes.NewBufferString(issue_19x_invalid))
|
||||
r.UseNumber()
|
||||
erre = r.Decode(&iobje2)
|
||||
require.Equal(t, erre, errs)
|
||||
require.Equal(t, iobje2, iobjs2)
|
||||
// spew.Dump(iobje2)
|
||||
}
|
||||
|
||||
var jsonNumberBig = "\"" + strings.Repeat("9", 10) + "." + strings.Repeat("9", 100) + "\""
|
||||
|
||||
func BenchmarkDecodeJsonNumber_Sonic(b *testing.B) {
|
||||
b.SetBytes(int64(len(jsonNumberBig)))
|
||||
b.ResetTimer()
|
||||
for i:=0; i<b.N; i++ {
|
||||
var obj json.Number
|
||||
_ = sonic.UnmarshalString(jsonNumberBig, &obj)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecodeUseNumber_Sonic(b *testing.B) {
|
||||
b.SetBytes(int64(len(jsonNumberBig)))
|
||||
b.ResetTimer()
|
||||
for i:=0; i<b.N; i++ {
|
||||
var obj interface{}
|
||||
dc := decoder.NewDecoder(jsonNumberBig)
|
||||
dc.UseNumber()
|
||||
_ = dc.Decode(&obj)
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,7 @@ ssize_t quote(const char *sp, ssize_t nb, char *dp, ssize_t *dn, uint64_t flags)
|
|||
ssize_t unquote(const char *sp, ssize_t nb, char *dp, ssize_t *ep, uint64_t flags);
|
||||
ssize_t html_escape(const char *sp, ssize_t nb, char *dp, ssize_t *dn);
|
||||
|
||||
long value(const char *s, size_t n, long p, JsonState *ret, int allow_control);
|
||||
long value(const char *s, size_t n, long p, JsonState *ret, uint64_t flags);
|
||||
void vstring(const GoString *src, long *p, JsonState *ret);
|
||||
void vnumber(const GoString *src, long *p, JsonState *ret);
|
||||
void vsigned(const GoString *src, long *p, JsonState *ret);
|
||||
|
|
@ -121,6 +121,7 @@ long skip_object(const GoString *src, long *p, StateMachine *m);
|
|||
long skip_string(const GoString *src, long *p);
|
||||
long skip_negative(const GoString *src, long *p);
|
||||
long skip_positive(const GoString *src, long *p);
|
||||
long skip_number(const GoString *src, long *p);
|
||||
|
||||
bool atof_eisel_lemire64(uint64_t mant, int exp10, int sgn, double *val);
|
||||
double atof_native(const char *sp, ssize_t nb, char* dbuf, ssize_t cap);
|
||||
|
|
|
|||
|
|
@ -51,8 +51,20 @@ static inline char isspace(char ch) {
|
|||
return ch == ' ' || ch == '\r' || ch == '\n' | ch == '\t';
|
||||
}
|
||||
|
||||
static inline void vdigits(const GoString *src, long *p, JsonState *ret) {
|
||||
const int MASK_USE_NUMBER = 1<<1;
|
||||
|
||||
static inline void vdigits(const GoString *src, long *p, JsonState *ret, uint64_t flag) {
|
||||
--*p;
|
||||
if (flag & MASK_USE_NUMBER) {
|
||||
long i = skip_number(src, p);
|
||||
if (i < 0) {
|
||||
ret->vt = i;
|
||||
return;
|
||||
}
|
||||
ret->vt = V_DOUBLE;
|
||||
ret->ep = i;
|
||||
return;
|
||||
}
|
||||
vnumber(src, p, ret);
|
||||
}
|
||||
|
||||
|
|
@ -572,9 +584,12 @@ static inline ssize_t advance_validate_string(const GoString *src, long p, int64
|
|||
|
||||
/** Value Scanning Routines **/
|
||||
|
||||
long value(const char *s, size_t n, long p, JsonState *ret, int allow_control) {
|
||||
const uint64_t MASK_ALLOW_CONTROL = 1ul<<31;
|
||||
|
||||
long value(const char *s, size_t n, long p, JsonState *ret, uint64_t flags) {
|
||||
long q = p;
|
||||
GoString m = {.buf = s, .len = n};
|
||||
bool allow_control = (flags&MASK_ALLOW_CONTROL) != 0;
|
||||
|
||||
/* parse the next identifier, q is UNSAFE, may cause out-of-bounds accessing */
|
||||
switch (advance_ns(&m, &q)) {
|
||||
|
|
@ -588,7 +603,7 @@ long value(const char *s, size_t n, long p, JsonState *ret, int allow_control) {
|
|||
case '6' : /* fallthrough */
|
||||
case '7' : /* fallthrough */
|
||||
case '8' : /* fallthrough */
|
||||
case '9' : vdigits(&m, &q, ret) ; return q;
|
||||
case '9' : vdigits(&m, &q, ret, flags) ; return q;
|
||||
case '"' : vstring(&m, &q, ret) ; return q;
|
||||
case 'n' : ret->vt = advance_dword(&m, &q, 1, V_NULL, VS_NULL) ; return q;
|
||||
case 't' : ret->vt = advance_dword(&m, &q, 1, V_TRUE, VS_TRUE) ; return q;
|
||||
|
|
@ -1135,7 +1150,7 @@ static inline long fsm_exec(StateMachine *self, const GoString *src, long *p, in
|
|||
} \
|
||||
}
|
||||
|
||||
static inline long skip_number(const char *sp, size_t nb) {
|
||||
static inline long do_skip_number(const char *sp, size_t nb) {
|
||||
long di = -1;
|
||||
long ei = -1;
|
||||
long si = -1;
|
||||
|
|
@ -1380,7 +1395,7 @@ long validate_string(const GoString *src, long *p) {
|
|||
|
||||
long skip_negative(const GoString *src, long *p) {
|
||||
long i = *p;
|
||||
long r = skip_number(src->buf + i, src->len - i);
|
||||
long r = do_skip_number(src->buf + i, src->len - i);
|
||||
|
||||
/* check for errors */
|
||||
if (r < 0) {
|
||||
|
|
@ -1395,7 +1410,7 @@ long skip_negative(const GoString *src, long *p) {
|
|||
|
||||
long skip_positive(const GoString *src, long *p) {
|
||||
long i = *p - 1;
|
||||
long r = skip_number(src->buf + i, src->len - i);
|
||||
long r = do_skip_number(src->buf + i, src->len - i);
|
||||
|
||||
/* check for errors */
|
||||
if (r < 0) {
|
||||
|
|
@ -1408,6 +1423,35 @@ long skip_positive(const GoString *src, long *p) {
|
|||
return i;
|
||||
}
|
||||
|
||||
long skip_number(const GoString *src, long *p) {
|
||||
const char* ss = src->buf;
|
||||
const char* sp = src->buf + *p;
|
||||
size_t nb = src->len;
|
||||
long i = *p;
|
||||
long r;
|
||||
bool neg = *sp == '-';
|
||||
|
||||
sp += neg;
|
||||
nb -= neg;
|
||||
if (unlikely(nb <= 0)) {
|
||||
*p = sp - ss;
|
||||
return -ERR_EOF;
|
||||
}
|
||||
|
||||
if (unlikely(i < nb && (*sp > '9' || *sp < '0'))) {
|
||||
*p = sp - ss;
|
||||
return -ERR_INVAL;
|
||||
}
|
||||
|
||||
r = do_skip_number(sp, nb);
|
||||
if (unlikely(r < 0)) {
|
||||
*p = sp - (r + 1) - ss;
|
||||
return -ERR_INVAL;
|
||||
}
|
||||
*p = sp + r - ss;
|
||||
return i;
|
||||
}
|
||||
|
||||
long validate_one(const GoString *src, long *p, StateMachine *m) {
|
||||
fsm_init(m, FSM_VAL);
|
||||
return fsm_exec(m, src, p, VALID_FULL);
|
||||
|
|
|
|||
Loading…
Reference in a new issue