diff options
author | 2025-01-14 13:10:39 +0000 | |
---|---|---|
committer | 2025-01-14 13:10:39 +0000 | |
commit | 4d423102c14de9e9328f1852db539d9561a3cad9 (patch) | |
tree | 6df5905f53ad7eadbfa9840939989253bfb4b199 /vendor/github.com/bytedance/sonic/internal/decoder/optdec | |
parent | [bugfix] migration to cleanup dropped status edits (#3637) (diff) | |
download | gotosocial-4d423102c14de9e9328f1852db539d9561a3cad9.tar.xz |
[chore]: Bump github.com/gin-contrib/gzip from 1.0.1 to 1.1.0 (#3639)
Bumps [github.com/gin-contrib/gzip](https://github.com/gin-contrib/gzip) from 1.0.1 to 1.1.0.
- [Release notes](https://github.com/gin-contrib/gzip/releases)
- [Changelog](https://github.com/gin-contrib/gzip/blob/master/.goreleaser.yaml)
- [Commits](https://github.com/gin-contrib/gzip/compare/v1.0.1...v1.1.0)
---
updated-dependencies:
- dependency-name: github.com/gin-contrib/gzip
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Diffstat (limited to 'vendor/github.com/bytedance/sonic/internal/decoder/optdec')
16 files changed, 4161 insertions, 0 deletions
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go new file mode 100644 index 000000000..713fb6561 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go @@ -0,0 +1,174 @@ +package optdec + +import ( + "fmt" + "reflect" + + caching "github.com/bytedance/sonic/internal/optcaching" + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/internal/resolver" +) + +const ( + _MAX_FIELDS = 50 // cutoff at 50 fields struct +) + +func (c *compiler) compileIntStringOption(vt reflect.Type) decFunc { + switch vt.Size() { + case 4: + switch vt.Kind() { + case reflect.Uint: + fallthrough + case reflect.Uintptr: + return &u32StringDecoder{} + case reflect.Int: + return &i32StringDecoder{} + } + case 8: + switch vt.Kind() { + case reflect.Uint: + fallthrough + case reflect.Uintptr: + return &u64StringDecoder{} + case reflect.Int: + return &i64StringDecoder{} + } + default: + panic("not supported pointer size: " + fmt.Sprint(vt.Size())) + } + panic("unreachable") +} + +func isInteger(vt reflect.Type) bool { + switch vt.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr, reflect.Int: return true + default: return false + } +} + +func (c *compiler) assertStringOptTypes(vt reflect.Type) { + if c.depth > _CompileMaxDepth { + panic(*stackOverflow) + } + + c.depth += 1 + defer func () { + c.depth -= 1 + }() + + if isInteger(vt) { + return + } + + switch vt.Kind() { + case reflect.String, reflect.Bool, reflect.Float32, reflect.Float64: + return + case reflect.Ptr: c.assertStringOptTypes(vt.Elem()) + default: + panicForInvalidStrType(vt) + } +} + +func (c *compiler) compileFieldStringOption(vt reflect.Type) decFunc { + c.assertStringOptTypes(vt) + unmDec := c.tryCompilePtrUnmarshaler(vt, true) + if unmDec != nil { + return unmDec + } + + switch vt.Kind() { + case reflect.String: + if vt == jsonNumberType { + return &numberStringDecoder{} + } + return &strStringDecoder{} + case reflect.Bool: + return &boolStringDecoder{} + case reflect.Int8: + return &i8StringDecoder{} + case reflect.Int16: + return &i16StringDecoder{} + case reflect.Int32: + return &i32StringDecoder{} + case reflect.Int64: + return &i64StringDecoder{} + case reflect.Uint8: + return &u8StringDecoder{} + case reflect.Uint16: + return &u16StringDecoder{} + case reflect.Uint32: + return &u32StringDecoder{} + case reflect.Uint64: + return &u64StringDecoder{} + case reflect.Float32: + return &f32StringDecoder{} + case reflect.Float64: + return &f64StringDecoder{} + case reflect.Uint: + fallthrough + case reflect.Uintptr: + fallthrough + case reflect.Int: + return c.compileIntStringOption(vt) + case reflect.Ptr: + return &ptrStrDecoder{ + typ: rt.UnpackType(vt.Elem()), + deref: c.compileFieldStringOption(vt.Elem()), + } + default: + panicForInvalidStrType(vt) + return nil + } +} + +func (c *compiler) compileStruct(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + if c.namedPtr { + c.namedPtr = false + return c.compileStructBody(vt) + } + + if c.depth >= c.opts.MaxInlineDepth + 1 || (c.counts > 0 && vt.NumField() >= _MAX_FIELDS) { + return &recuriveDecoder{ + typ: rt.UnpackType(vt), + } + } else { + return c.compileStructBody(vt) + } +} + +func (c *compiler) compileStructBody(vt reflect.Type) decFunc { + fv := resolver.ResolveStruct(vt) + entries := make([]fieldEntry, 0, len(fv)) + + for _, f := range fv { + var dec decFunc + /* dealt with field tag options */ + if f.Opts&resolver.F_stringize != 0 { + dec = c.compileFieldStringOption(f.Type) + } else { + dec = c.compile(f.Type) + } + + /* deal with embedded pointer fields */ + if f.Path[0].Kind == resolver.F_deref { + dec = &embeddedFieldPtrDecoder{ + field: f, + fieldDec: dec, + fieldName: f.Name, + } + } + + entries = append(entries, fieldEntry{ + FieldMeta: f, + fieldDec: dec, + }) + } + return &structDecoder{ + fieldMap: caching.NewFieldLookup(fv), + fields: entries, + structName: vt.Name(), + typ: vt, + } +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go new file mode 100644 index 000000000..fd164af93 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go @@ -0,0 +1,449 @@ +package optdec + +import ( + "encoding/json" + "fmt" + "reflect" + + "github.com/bytedance/sonic/option" + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/internal/caching" +) + +var ( + programCache = caching.CreateProgramCache() +) + +func findOrCompile(vt *rt.GoType) (decFunc, error) { + makeDecoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) { + ret, err := newCompiler().compileType(vt.Pack()) + return ret, err + } + if val := programCache.Get(vt); val != nil { + return val.(decFunc), nil + } else if ret, err := programCache.Compute(vt, makeDecoder); err == nil { + return ret.(decFunc), nil + } else { + return nil, err + } +} + +type compiler struct { + visited map[reflect.Type]bool + depth int + counts int + opts option.CompileOptions + namedPtr bool +} + +func newCompiler() *compiler { + return &compiler{ + visited: make(map[reflect.Type]bool), + opts: option.DefaultCompileOptions(), + } +} + +func (self *compiler) apply(opts option.CompileOptions) *compiler { + self.opts = opts + return self +} + +const _CompileMaxDepth = 4096 + +func (c *compiler) enter(vt reflect.Type) { + c.visited[vt] = true + c.depth += 1 + + if c.depth > _CompileMaxDepth { + panic(*stackOverflow) + } +} + +func (c *compiler) exit(vt reflect.Type) { + c.visited[vt] = false + c.depth -= 1 +} + +func (c *compiler) compileInt(vt reflect.Type) decFunc { + switch vt.Size() { + case 4: + switch vt.Kind() { + case reflect.Uint: + fallthrough + case reflect.Uintptr: + return &u32Decoder{} + case reflect.Int: + return &i32Decoder{} + } + case 8: + switch vt.Kind() { + case reflect.Uint: + fallthrough + case reflect.Uintptr: + return &u64Decoder{} + case reflect.Int: + return &i64Decoder{} + } + default: + panic("not supported pointer size: " + fmt.Sprint(vt.Size())) + } + panic("unreachable") +} + +func (c *compiler) rescue(ep *error) { + if val := recover(); val != nil { + if err, ok := val.(error); ok { + *ep = err + } else { + panic(val) + } + } +} + +func (c *compiler) compileType(vt reflect.Type) (rt decFunc, err error) { + defer c.rescue(&err) + rt = c.compile(vt) + return rt, err +} + +func (c *compiler) compile(vt reflect.Type) decFunc { + if c.visited[vt] { + return &recuriveDecoder{ + typ: rt.UnpackType(vt), + } + } + + dec := c.tryCompilePtrUnmarshaler(vt, false) + if dec != nil { + return dec + } + + return c.compileBasic(vt) +} + +func (c *compiler) compileBasic(vt reflect.Type) decFunc { + defer func() { + c.counts += 1 + }() + switch vt.Kind() { + case reflect.Bool: + return &boolDecoder{} + case reflect.Int8: + return &i8Decoder{} + case reflect.Int16: + return &i16Decoder{} + case reflect.Int32: + return &i32Decoder{} + case reflect.Int64: + return &i64Decoder{} + case reflect.Uint8: + return &u8Decoder{} + case reflect.Uint16: + return &u16Decoder{} + case reflect.Uint32: + return &u32Decoder{} + case reflect.Uint64: + return &u64Decoder{} + case reflect.Float32: + return &f32Decoder{} + case reflect.Float64: + return &f64Decoder{} + case reflect.Uint: + fallthrough + case reflect.Uintptr: + fallthrough + case reflect.Int: + return c.compileInt(vt) + case reflect.String: + return c.compileString(vt) + case reflect.Array: + return c.compileArray(vt) + case reflect.Interface: + return c.compileInterface(vt) + case reflect.Map: + return c.compileMap(vt) + case reflect.Ptr: + return c.compilePtr(vt) + case reflect.Slice: + return c.compileSlice(vt) + case reflect.Struct: + return c.compileStruct(vt) + default: + panic(&json.UnmarshalTypeError{Type: vt}) + } +} + +func (c *compiler) compilePtr(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + + // specail logic for Named Ptr, issue 379 + if reflect.PtrTo(vt.Elem()) != vt { + c.namedPtr = true + return &ptrDecoder{ + typ: rt.UnpackType(vt.Elem()), + deref: c.compileBasic(vt.Elem()), + } + } + + return &ptrDecoder{ + typ: rt.UnpackType(vt.Elem()), + deref: c.compile(vt.Elem()), + } +} + +func (c *compiler) compileArray(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + return &arrayDecoder{ + len: vt.Len(), + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } +} + +func (c *compiler) compileString(vt reflect.Type) decFunc { + if vt == jsonNumberType { + return &numberDecoder{} + } + return &stringDecoder{} + +} + +func (c *compiler) tryCompileSliceUnmarshaler(vt reflect.Type) decFunc { + pt := reflect.PtrTo(vt.Elem()) + if pt.Implements(jsonUnmarshalerType) { + return &sliceDecoder{ + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } + } + + if pt.Implements(encodingTextUnmarshalerType) { + return &sliceDecoder{ + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } + } + return nil +} + +func (c *compiler) compileSlice(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + + // Some common slice, use a decoder, to avoid function calls + et := rt.UnpackType(vt.Elem()) + + /* first checking `[]byte` */ + if et.Kind() == reflect.Uint8 /* []byte */ { + return c.compileSliceBytes(vt) + } + + dec := c.tryCompileSliceUnmarshaler(vt) + if dec != nil { + return dec + } + + if vt == reflect.TypeOf([]interface{}{}) { + return &sliceEfaceDecoder{} + } + if et.IsInt32() { + return &sliceI32Decoder{} + } + if et.IsInt64() { + return &sliceI64Decoder{} + } + if et.IsUint32() { + return &sliceU32Decoder{} + } + if et.IsUint64() { + return &sliceU64Decoder{} + } + if et.Kind() == reflect.String { + return &sliceStringDecoder{} + } + + return &sliceDecoder{ + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } +} + +func (c *compiler) compileSliceBytes(vt reflect.Type) decFunc { + ep := reflect.PtrTo(vt.Elem()) + + if ep.Implements(jsonUnmarshalerType) { + return &sliceBytesUnmarshalerDecoder{ + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } + } + + if ep.Implements(encodingTextUnmarshalerType) { + return &sliceBytesUnmarshalerDecoder{ + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } + } + + return &sliceBytesDecoder{} +} + +func (c *compiler) compileInterface(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + if vt.NumMethod() == 0 { + return &efaceDecoder{} + } + + if vt.Implements(jsonUnmarshalerType) { + return &unmarshalJSONDecoder{ + typ: rt.UnpackType(vt), + } + } + + if vt.Implements(encodingTextUnmarshalerType) { + return &unmarshalTextDecoder{ + typ: rt.UnpackType(vt), + } + } + + return &ifaceDecoder{ + typ: rt.UnpackType(vt), + } +} + +func (c *compiler) compileMap(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + // check the key unmarshaler at first + decKey := tryCompileKeyUnmarshaler(vt) + if decKey != nil { + return &mapDecoder{ + mapType: rt.MapType(rt.UnpackType(vt)), + keyDec: decKey, + elemDec: c.compile(vt.Elem()), + } + } + + // Most common map, use a decoder, to avoid function calls + if vt == reflect.TypeOf(map[string]interface{}{}) { + return &mapEfaceDecoder{} + } else if vt == reflect.TypeOf(map[string]string{}) { + return &mapStringDecoder{} + } + + // Some common integer map later + mt := rt.MapType(rt.UnpackType(vt)) + + if mt.Key.Kind() == reflect.String { + return &mapStrKeyDecoder{ + mapType: mt, + assign: rt.GetMapStrAssign(vt), + elemDec: c.compile(vt.Elem()), + } + } + + if mt.Key.IsInt64() { + return &mapI64KeyDecoder{ + mapType: mt, + elemDec: c.compile(vt.Elem()), + assign: rt.GetMap64Assign(vt), + } + } + + if mt.Key.IsInt32() { + return &mapI32KeyDecoder{ + mapType: mt, + elemDec: c.compile(vt.Elem()), + assign: rt.GetMap32Assign(vt), + } + } + + if mt.Key.IsUint64() { + return &mapU64KeyDecoder{ + mapType: mt, + elemDec: c.compile(vt.Elem()), + assign: rt.GetMap64Assign(vt), + } + } + + if mt.Key.IsUint32() { + return &mapU32KeyDecoder{ + mapType: mt, + elemDec: c.compile(vt.Elem()), + assign: rt.GetMap32Assign(vt), + } + } + + // Generic map + return &mapDecoder{ + mapType: mt, + keyDec: c.compileMapKey(vt), + elemDec: c.compile(vt.Elem()), + } +} + +func tryCompileKeyUnmarshaler(vt reflect.Type) decKey { + pt := reflect.PtrTo(vt.Key()) + + /* check for `encoding.TextUnmarshaler` with pointer receiver */ + if pt.Implements(encodingTextUnmarshalerType) { + return decodeKeyTextUnmarshaler + } + + /* not support map key with `json.Unmarshaler` */ + return nil +} + +func (c *compiler) compileMapKey(vt reflect.Type) decKey { + switch vt.Key().Kind() { + case reflect.Int8: + return decodeKeyI8 + case reflect.Int16: + return decodeKeyI16 + case reflect.Uint8: + return decodeKeyU8 + case reflect.Uint16: + return decodeKeyU16 + default: + panic(&json.UnmarshalTypeError{Type: vt}) + } +} + +// maybe vt is a named type, and not a pointer receiver, see issue 379 +func (c *compiler) tryCompilePtrUnmarshaler(vt reflect.Type, strOpt bool) decFunc { + pt := reflect.PtrTo(vt) + + /* check for `json.Unmarshaler` with pointer receiver */ + if pt.Implements(jsonUnmarshalerType) { + return &unmarshalJSONDecoder{ + typ: rt.UnpackType(pt), + strOpt: strOpt, + } + } + + /* check for `encoding.TextMarshaler` with pointer receiver */ + if pt.Implements(encodingTextUnmarshalerType) { + /* TextUnmarshal not support ,strig tag */ + if strOpt { + panicForInvalidStrType(vt) + } + return &unmarshalTextDecoder{ + typ: rt.UnpackType(pt), + } + } + + return nil +} + +func panicForInvalidStrType(vt reflect.Type) { + panic(error_type(rt.UnpackType(vt))) +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go new file mode 100644 index 000000000..77879fafe --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go @@ -0,0 +1,60 @@ +package optdec + +import "math" + +/* +Copied from sonic-rs +// JSON Value Type +const NULL: u64 = 0; +const BOOL: u64 = 2; +const FALSE: u64 = BOOL; +const TRUE: u64 = (1 << 3) | BOOL; +const NUMBER: u64 = 3; +const UINT: u64 = NUMBER; +const SINT: u64 = (1 << 3) | NUMBER; +const REAL: u64 = (2 << 3) | NUMBER; +const RAWNUMBER: u64 = (3 << 3) | NUMBER; +const STRING: u64 = 4; +const STRING_COMMON: u64 = STRING; +const STRING_HASESCAPED: u64 = (1 << 3) | STRING; +const OBJECT: u64 = 6; +const ARRAY: u64 = 7; + +/// JSON Type Mask +const POS_MASK: u64 = (!0) << 32; +const POS_BITS: u64 = 32; +const TYPE_MASK: u64 = 0xFF; +const TYPE_BITS: u64 = 8; + +*/ + +const ( + // BasicType: 3 bits + KNull = 0 // xxxxx000 + KBool = 2 // xxxxx010 + KNumber = 3 // xxxxx011 + KString = 4 // xxxxx100 + KRaw = 5 // xxxxx101 + KObject = 6 // xxxxx110 + KArray = 7 // xxxxx111 + + // SubType: 2 bits + KFalse = (0 << 3) | KBool // xxx00_010, 2 + KTrue = (1 << 3) | KBool // xxx01_010, 10 + KUint = (0 << 3) | KNumber // xxx00_011, 3 + KSint = (1 << 3) | KNumber // xxx01_011, 11 + KReal = (2 << 3) | KNumber // xxx10_011, 19 + KRawNumber = (3 << 3) | KNumber // xxx11_011, 27 + KStringCommon = KString // xxx00_100, 4 + KStringEscaped = (1 << 3) | KString // xxx01_100, 12 +) + +const ( + PosMask = math.MaxUint64 << 32 + PosBits = 32 + TypeMask = 0xFF + TypeBits = 8 + + ConLenMask = uint64(math.MaxUint32) + ConLenBits = 32 +) diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go new file mode 100644 index 000000000..93ed9b7e0 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go @@ -0,0 +1,3 @@ +package optdec + +type context = Context diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go new file mode 100644 index 000000000..81eed34ea --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go @@ -0,0 +1,160 @@ +package optdec + +import ( + "reflect" + "unsafe" + + "encoding/json" + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/option" + "github.com/bytedance/sonic/internal/decoder/errors" + "github.com/bytedance/sonic/internal/decoder/consts" +) + + +type ( + MismatchTypeError = errors.MismatchTypeError + SyntaxError = errors.SyntaxError +) + +const ( + _F_allow_control = consts.F_allow_control + _F_copy_string = consts.F_copy_string + _F_disable_unknown = consts.F_disable_unknown + _F_disable_urc = consts.F_disable_urc + _F_use_int64 = consts.F_use_int64 + _F_use_number = consts.F_use_number + _F_validate_string = consts.F_validate_string +) + +type Options = consts.Options + +const ( + OptionUseInt64 = consts.OptionUseInt64 + OptionUseNumber = consts.OptionUseNumber + OptionUseUnicodeErrors = consts.OptionUseUnicodeErrors + OptionDisableUnknown = consts.OptionDisableUnknown + OptionCopyString = consts.OptionCopyString + OptionValidateString = consts.OptionValidateString +) + + +func Decode(s *string, i *int, f uint64, val interface{}) error { + vv := rt.UnpackEface(val) + vp := vv.Value + + /* check for nil type */ + if vv.Type == nil { + return &json.InvalidUnmarshalError{} + } + + /* must be a non-nil pointer */ + if vp == nil || vv.Type.Kind() != reflect.Ptr { + return &json.InvalidUnmarshalError{Type: vv.Type.Pack()} + } + + etp := rt.PtrElem(vv.Type) + + /* check the defined pointer type for issue 379 */ + if vv.Type.IsNamed() { + newp := vp + etp = vv.Type + vp = unsafe.Pointer(&newp) + } + + dec, err := findOrCompile(etp) + if err != nil { + return err + } + + /* parse into document */ + ctx, err := NewContext(*s, *i, uint64(f), etp) + defer ctx.Delete() + if ctx.Parser.Utf8Inv { + *s = ctx.Parser.Json + } + if err != nil { + goto fix_error; + } + err = dec.FromDom(vp, ctx.Root(), &ctx) + +fix_error: + err = fix_error(*s, *i, err) + + // update position at last + *i += ctx.Parser.Pos() + return err +} + +func fix_error(json string, pos int, err error) error { + if e, ok := err.(SyntaxError); ok { + return SyntaxError{ + Pos: int(e.Pos) + pos, + Src: json, + Msg: e.Msg, + } + } + + if e, ok := err.(MismatchTypeError); ok { + return &MismatchTypeError { + Pos: int(e.Pos) + pos, + Src: json, + Type: e.Type, + } + } + + return err +} + +// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in +// order to reduce the first-hit latency. +// +// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is +// a compile option to set the depth of recursive compile for the nested struct type. +func Pretouch(vt reflect.Type, opts ...option.CompileOption) error { + cfg := option.DefaultCompileOptions() + for _, opt := range opts { + opt(&cfg) + } + return pretouchRec(map[reflect.Type]bool{vt:true}, cfg) +} + +func pretouchType(_vt reflect.Type, opts option.CompileOptions) (map[reflect.Type]bool, error) { + /* compile function */ + compiler := newCompiler().apply(opts) + decoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) { + if f, err := compiler.compileType(_vt); err != nil { + return nil, err + } else { + return f, nil + } + } + + /* find or compile */ + vt := rt.UnpackType(_vt) + if val := programCache.Get(vt); val != nil { + return nil, nil + } else if _, err := programCache.Compute(vt, decoder); err == nil { + return compiler.visited, nil + } else { + return nil, err + } +} + +func pretouchRec(vtm map[reflect.Type]bool, opts option.CompileOptions) error { + if opts.RecursiveDepth < 0 || len(vtm) == 0 { + return nil + } + next := make(map[reflect.Type]bool) + for vt := range(vtm) { + sub, err := pretouchType(vt, opts) + if err != nil { + return err + } + for svt := range(sub) { + next[svt] = true + } + } + opts.RecursiveDepth -= 1 + return pretouchRec(next, opts) +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go new file mode 100644 index 000000000..db0af547b --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go @@ -0,0 +1,73 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package optdec + + import ( + "encoding/json" + "errors" + "reflect" + "strconv" + + "github.com/bytedance/sonic/internal/rt" + ) + + /** JIT Error Helpers **/ + + var stackOverflow = &json.UnsupportedValueError{ + Str: "Value nesting too deep", + Value: reflect.ValueOf("..."), + } + + func error_type(vt *rt.GoType) error { + return &json.UnmarshalTypeError{Type: vt.Pack()} + } + + func error_mismatch(node Node, ctx *context, typ reflect.Type) error { + return MismatchTypeError{ + Pos: node.Position(), + Src: ctx.Parser.Json, + Type: typ, + } + } + + func newUnmatched(pos int, vt *rt.GoType) error { + return MismatchTypeError{ + Pos: pos, + Src: "", + Type: vt.Pack(), + } + } + + func error_field(name string) error { + return errors.New("json: unknown field " + strconv.Quote(name)) + } + + func error_value(value string, vtype reflect.Type) error { + return &json.UnmarshalTypeError{ + Type: vtype, + Value: value, + } + } + + func error_syntax(pos int, src string, msg string) error { + return SyntaxError{ + Pos: pos, + Src: src, + Msg: msg, + } + } +
\ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go new file mode 100644 index 000000000..2a0523d5e --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go @@ -0,0 +1,281 @@ +package optdec + +import ( + "encoding/json" + "math" + "unsafe" + + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/internal/resolver" +) + +type decFunc interface { + FromDom(vp unsafe.Pointer, node Node, ctx *context) error +} + +type ptrDecoder struct { + typ *rt.GoType + deref decFunc +} + +// Pointer Value is allocated in the Caller +func (d *ptrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + if *(*unsafe.Pointer)(vp) == nil { + *(*unsafe.Pointer)(vp) = rt.Mallocgc(d.typ.Size, d.typ, true) + } + + return d.deref.FromDom(*(*unsafe.Pointer)(vp), node, ctx) +} + +type embeddedFieldPtrDecoder struct { + field resolver.FieldMeta + fieldDec decFunc + fieldName string +} + +// Pointer Value is allocated in the Caller +func (d *embeddedFieldPtrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + // seek into the pointer + vp = unsafe.Pointer(uintptr(vp) - uintptr(d.field.Path[0].Size)) + for _, f := range d.field.Path { + deref := rt.UnpackType(f.Type) + vp = unsafe.Pointer(uintptr(vp) + f.Size) + if f.Kind == resolver.F_deref { + if *(*unsafe.Pointer)(vp) == nil { + *(*unsafe.Pointer)(vp) = rt.Mallocgc(deref.Size, deref, true) + } + vp = *(*unsafe.Pointer)(vp) + } + } + return d.fieldDec.FromDom(vp, node, ctx) +} + +type i8Decoder struct{} + +func (d *i8Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsI64(ctx) + if !ok || ret > math.MaxInt8 || ret < math.MinInt8 { + return error_mismatch(node, ctx, int8Type) + } + + *(*int8)(vp) = int8(ret) + return nil +} + +type i16Decoder struct{} + +func (d *i16Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsI64(ctx) + if !ok || ret > math.MaxInt16 || ret < math.MinInt16 { + return error_mismatch(node, ctx, int16Type) + } + + *(*int16)(vp) = int16(ret) + return nil +} + +type i32Decoder struct{} + +func (d *i32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsI64(ctx) + if !ok || ret > math.MaxInt32 || ret < math.MinInt32 { + return error_mismatch(node, ctx, int32Type) + } + + *(*int32)(vp) = int32(ret) + return nil +} + +type i64Decoder struct{} + +func (d *i64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsI64(ctx) + if !ok { + return error_mismatch(node, ctx, int64Type) + } + + *(*int64)(vp) = int64(ret) + return nil +} + +type u8Decoder struct{} + +func (d *u8Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsU64(ctx) + if !ok || ret > math.MaxUint8 { + err := error_mismatch(node, ctx, uint8Type) + return err + } + + *(*uint8)(vp) = uint8(ret) + return nil +} + +type u16Decoder struct{} + +func (d *u16Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsU64(ctx) + if !ok || ret > math.MaxUint16 { + return error_mismatch(node, ctx, uint16Type) + } + *(*uint16)(vp) = uint16(ret) + return nil +} + +type u32Decoder struct{} + +func (d *u32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsU64(ctx) + if !ok || ret > math.MaxUint32 { + return error_mismatch(node, ctx, uint32Type) + } + + *(*uint32)(vp) = uint32(ret) + return nil +} + +type u64Decoder struct{} + +func (d *u64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsU64(ctx) + if !ok { + return error_mismatch(node, ctx, uint64Type) + } + + *(*uint64)(vp) = uint64(ret) + return nil +} + +type f32Decoder struct{} + +func (d *f32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsF64(ctx) + if !ok || ret > math.MaxFloat32 || ret < -math.MaxFloat32 { + return error_mismatch(node, ctx, float32Type) + } + + *(*float32)(vp) = float32(ret) + return nil +} + +type f64Decoder struct{} + +func (d *f64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsF64(ctx) + if !ok { + return error_mismatch(node, ctx, float64Type) + } + + *(*float64)(vp) = float64(ret) + return nil +} + +type boolDecoder struct { +} + +func (d *boolDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsBool() + if !ok { + return error_mismatch(node, ctx, boolType) + } + + *(*bool)(vp) = bool(ret) + return nil +} + +type stringDecoder struct { +} + +func (d *stringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsStr(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + *(*string)(vp) = ret + return nil +} + +type numberDecoder struct { +} + +func (d *numberDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + num, ok := node.AsNumber(ctx) + if !ok { + return error_mismatch(node, ctx, jsonNumberType) + } + *(*json.Number)(vp) = num + return nil +} + +type recuriveDecoder struct { + typ *rt.GoType +} + +func (d *recuriveDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + dec, err := findOrCompile(d.typ) + if err != nil { + return err + } + return dec.FromDom(vp, node, ctx) +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go new file mode 100644 index 000000000..7bf8a8f39 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go @@ -0,0 +1,110 @@ +package optdec + +import ( + "encoding/json" + "strconv" + + "github.com/bytedance/sonic/internal/native" + "github.com/bytedance/sonic/internal/utils" + "github.com/bytedance/sonic/internal/native/types" +) + + +func SkipNumberFast(json string, start int) (int, bool) { + // find the number ending, we pasred in native, it alway valid + pos := start + for pos < len(json) && json[pos] != ']' && json[pos] != '}' && json[pos] != ',' { + if json[pos] >= '0' && json[pos] <= '9' || json[pos] == '.' || json[pos] == '-' || json[pos] == '+' || json[pos] == 'e' || json[pos] == 'E' { + pos += 1 + } else { + break + } + } + + // if not found number, return false + if pos == start { + return pos, false + } + return pos, true +} + + +func isSpace(c byte) bool { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' +} + +// pos is the start index of the raw +func ValidNumberFast(raw string) bool { + ret := utils.SkipNumber(raw, 0) + if ret < 0 { + return false + } + + // check trainling chars + for ret < len(raw) { + return false + } + + return true +} + +func SkipOneFast2(json string, pos *int) (int, error) { + // find the number ending, we pasred in sonic-cpp, it alway valid + start := native.SkipOneFast(&json, pos) + if start < 0 { + return -1, error_syntax(*pos, json, types.ParsingError(-start).Error()) + } + return start, nil +} + +func SkipOneFast(json string, pos int) (string, error) { + // find the number ending, we pasred in sonic-cpp, it alway valid + start := native.SkipOneFast(&json, &pos) + if start < 0 { + // TODO: details error code + return "", error_syntax(pos, json, types.ParsingError(-start).Error()) + } + return json[start:pos], nil +} + +func ParseI64(raw string) (int64, error) { + i64, err := strconv.ParseInt(raw, 10, 64) + if err != nil { + return 0, err + } + return i64, nil +} + +func ParseBool(raw string) (bool, error) { + var b bool + err := json.Unmarshal([]byte(raw), &b) + if err != nil { + return false, err + } + return b, nil +} + +func ParseU64(raw string) (uint64, error) { + u64, err := strconv.ParseUint(raw, 10, 64) + if err != nil { + return 0, err + } + return u64, nil +} + +func ParseF64(raw string) (float64, error) { + f64, err := strconv.ParseFloat(raw, 64) + if err != nil { + return 0, err + } + return f64, nil +} + +func Unquote(raw string) (string, error) { + var u string + err := json.Unmarshal([]byte(raw), &u) + if err != nil { + return "", err + } + return u, nil +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go new file mode 100644 index 000000000..0c063d55f --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go @@ -0,0 +1,169 @@ +package optdec + +import ( + "encoding" + "encoding/json" + "unsafe" + "reflect" + + "github.com/bytedance/sonic/internal/rt" +) + +type efaceDecoder struct { +} + +func (d *efaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*interface{})(vp) = interface{}(nil) + return nil + } + + eface := *(*rt.GoEface)(vp) + + // not pointer type, or nil pointer, or *interface{} + if eface.Value == nil || eface.Type.Kind() != reflect.Ptr || rt.PtrElem(eface.Type) == anyType { + ret, err := node.AsEface(ctx) + if err != nil { + return err + } + + *(*interface{})(vp) = ret + return nil + } + + etp := rt.PtrElem(eface.Type) + vp = eface.Value + + /* check the defined pointer type for issue 379 */ + if eface.Type.IsNamed() { + newp := vp + etp = eface.Type + vp = unsafe.Pointer(&newp) + } + + dec, err := findOrCompile(etp) + if err != nil { + return err + } + + return dec.FromDom(vp, node, ctx) +} + +type ifaceDecoder struct { + typ *rt.GoType +} + +func (d *ifaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + iface := *(*rt.GoIface)(vp) + if iface.Itab == nil { + return error_type(d.typ) + } + + vt := iface.Itab.Vt + + // not pointer type, or nil pointer, or *interface{} + if vp == nil || vt.Kind() != reflect.Ptr || rt.PtrElem(vt) == anyType { + ret, err := node.AsEface(ctx) + if err != nil { + return err + } + + *(*interface{})(vp) = ret + return nil + } + + + etp := rt.PtrElem(vt) + vp = iface.Value + + /* check the defined pointer type for issue 379 */ + if vt.IsNamed() { + newp := vp + etp = vt + vp = unsafe.Pointer(&newp) + } + + dec, err := findOrCompile(etp) + if err != nil { + return err + } + + return dec.FromDom(vp, node, ctx) +} + +type unmarshalTextDecoder struct { + typ *rt.GoType +} + +func (d *unmarshalTextDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + txt, ok := node.AsStringText(ctx) + if !ok { + return error_mismatch(node, ctx, d.typ.Pack()) + } + + v := *(*interface{})(unsafe.Pointer(&rt.GoEface{ + Type: d.typ, + Value: vp, + })) + + // fast path + if u, ok := v.(encoding.TextUnmarshaler); ok { + return u.UnmarshalText(txt) + } + + // slow path + rv := reflect.ValueOf(v) + if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok { + return u.UnmarshalText(txt) + } + + return error_type(d.typ) +} + +type unmarshalJSONDecoder struct { + typ *rt.GoType + strOpt bool +} + +func (d *unmarshalJSONDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + v := *(*interface{})(unsafe.Pointer(&rt.GoEface{ + Type: d.typ, + Value: vp, + })) + + var input []byte + if d.strOpt && node.IsNull() { + input = []byte("null") + } else if d.strOpt { + s, ok := node.AsStringText(ctx) + if !ok { + return error_mismatch(node, ctx, d.typ.Pack()) + } + input = s + } else { + input = []byte(node.AsRaw(ctx)) + } + + // fast path + if u, ok := v.(json.Unmarshaler); ok { + return u.UnmarshalJSON((input)) + } + + // slow path + rv := reflect.ValueOf(v) + if u, ok := rv.Interface().(json.Unmarshaler); ok { + return u.UnmarshalJSON(input) + } + + return error_type(d.typ) +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go new file mode 100644 index 000000000..1a2bda8f3 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go @@ -0,0 +1,430 @@ +package optdec + +import ( + "encoding" + "encoding/json" + "math" + "reflect" + "unsafe" + + "github.com/bytedance/sonic/internal/rt" +) + +/** Decoder for most common map types: map[string]interface{}, map[string]string **/ + +type mapEfaceDecoder struct { +} + +func (d *mapEfaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*map[string]interface{})(vp) = nil + return nil + } + + return node.AsMapEface(ctx, vp) +} + +type mapStringDecoder struct { +} + +func (d *mapStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*map[string]string)(vp) = nil + return nil + } + + return node.AsMapString(ctx, vp) +} + +/** Decoder for map with string key **/ + +type mapStrKeyDecoder struct { + mapType *rt.GoMapType + elemDec decFunc + assign rt.MapStrAssign + typ reflect.Type +} + +func (d *mapStrKeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + var gerr error + next := obj.Children() + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + key, _ := keyn.AsStr(ctx) + + valn := NewNode(PtrOffset(next, 1)) + valp := d.assign(d.mapType, m, key) + err := d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} + +/** Decoder for map with int32 or int64 key **/ + +type mapI32KeyDecoder struct { + mapType *rt.GoMapType + elemDec decFunc + assign rt.Map32Assign +} + +func (d *mapI32KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + next := obj.Children() + var gerr error + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + k, ok := keyn.ParseI64(ctx) + if !ok || k > math.MaxInt32 || k < math.MinInt32 { + if gerr == nil { + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) + } + valn := NewNode(PtrOffset(next, 1)) + next = valn.Next() + continue + } + + key := int32(k) + ku32 := *(*uint32)(unsafe.Pointer(&key)) + valn := NewNode(PtrOffset(next, 1)) + valp := d.assign(d.mapType, m, ku32) + err := d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} + +type mapI64KeyDecoder struct { + mapType *rt.GoMapType + elemDec decFunc + assign rt.Map64Assign +} + +func (d *mapI64KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + var gerr error + next := obj.Children() + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + key, ok := keyn.ParseI64(ctx) + + if !ok { + if gerr == nil { + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) + } + valn := NewNode(PtrOffset(next, 1)) + next = valn.Next() + continue + } + + ku64 := *(*uint64)(unsafe.Pointer(&key)) + valn := NewNode(PtrOffset(next, 1)) + valp := d.assign(d.mapType, m, ku64) + err := d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} + +/** Decoder for map with unt32 or uint64 key **/ + +type mapU32KeyDecoder struct { + mapType *rt.GoMapType + elemDec decFunc + assign rt.Map32Assign +} + +func (d *mapU32KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + var gerr error + next := obj.Children() + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + k, ok := keyn.ParseU64(ctx) + if !ok || k > math.MaxUint32 { + if gerr == nil { + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) + } + valn := NewNode(PtrOffset(next, 1)) + next = valn.Next() + continue + } + + key := uint32(k) + valn := NewNode(PtrOffset(next, 1)) + valp := d.assign(d.mapType, m, key) + err := d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} + +type mapU64KeyDecoder struct { + mapType *rt.GoMapType + elemDec decFunc + assign rt.Map64Assign +} + +func (d *mapU64KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + var gerr error + next := obj.Children() + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + key, ok := keyn.ParseU64(ctx) + if !ok { + if gerr == nil { + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) + } + valn := NewNode(PtrOffset(next, 1)) + next = valn.Next() + continue + } + + valn := NewNode(PtrOffset(next, 1)) + valp := d.assign(d.mapType, m, key) + err := d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} + +/** Decoder for generic cases */ + +type decKey func(dec *mapDecoder, raw string, ctx *context) (interface{}, error) + +func decodeKeyU8(dec *mapDecoder, raw string, ctx *context) (interface{}, error) { + key, err := Unquote(raw) + if err != nil { + return nil, err + } + ret, err := ParseU64(key) + if err != nil { + return nil, err + } + if ret > math.MaxUint8 { + return nil, error_value(key, dec.mapType.Key.Pack()) + } + return uint8(ret), nil +} + +func decodeKeyU16(dec *mapDecoder, raw string, ctx *context) (interface{}, error) { + key, err := Unquote(raw) + if err != nil { + return nil, err + } + ret, err := ParseU64(key) + if err != nil { + return nil, err + } + if ret > math.MaxUint16 { + return nil, error_value(key, dec.mapType.Key.Pack()) + } + return uint16(ret), nil +} + +func decodeKeyI8(dec *mapDecoder, raw string, ctx *context) (interface{}, error) { + key, err := Unquote(raw) + if err != nil { + return nil, err + } + ret, err := ParseI64(key) + if err != nil { + return nil, err + } + if ret > math.MaxInt8 || ret < math.MinInt8 { + return nil, error_value(key, dec.mapType.Key.Pack()) + } + return int8(ret), nil +} + +func decodeKeyI16(dec *mapDecoder, raw string, ctx *context) (interface{}, error) { + key, err := Unquote(raw) + if err != nil { + return nil, err + } + ret, err := ParseI64(key) + if err != nil { + return nil, err + } + if ret > math.MaxInt16 || ret < math.MinInt16 { + return nil, error_value(key, dec.mapType.Key.Pack()) + } + return int16(ret), nil +} + +func decodeKeyJSONUnmarshaler(dec *mapDecoder, raw string, _ *context) (interface{}, error) { + ret := reflect.New(dec.mapType.Key.Pack()).Interface() + err := ret.(json.Unmarshaler).UnmarshalJSON([]byte(raw)) + if err != nil { + return nil, err + } + return ret, nil +} + +func decodeKeyTextUnmarshaler(dec *mapDecoder, raw string, ctx *context) (interface{}, error) { + key, err := Unquote(raw) + if err != nil { + return nil, err + } + ret := reflect.New(dec.mapType.Key.Pack()).Interface() + err = ret.(encoding.TextUnmarshaler).UnmarshalText([]byte(key)) + if err != nil { + return nil, err + } + return ret, nil +} + +type mapDecoder struct { + mapType *rt.GoMapType + keyDec decKey + elemDec decFunc +} + +func (d *mapDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + next := obj.Children() + var gerr error + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + raw := keyn.AsRaw(ctx) + key, err := d.keyDec(d, raw, ctx) + if err != nil { + if gerr == nil { + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) + } + valn := NewNode(PtrOffset(next, 1)) + next = valn.Next() + continue + } + + valn := NewNode(PtrOffset(next, 1)) + keyp := rt.UnpackEface(key).Value + valp := rt.Mapassign(d.mapType, m, keyp) + err = d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go new file mode 100644 index 000000000..29a0136ae --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go @@ -0,0 +1,269 @@ +package optdec + +import ( + "fmt" + "reflect" + "unsafe" + + "sync" + + "github.com/bytedance/sonic/internal/native" + "github.com/bytedance/sonic/internal/native/types" + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/utf8" +) + + +type ErrorCode int + +const ( + SONIC_OK = 0; + SONIC_CONTROL_CHAR = 1; + SONIC_INVALID_ESCAPED = 2; + SONIC_INVALID_NUM = 3; + SONIC_FLOAT_INF = 4; + SONIC_EOF = 5; + SONIC_INVALID_CHAR = 6; + SONIC_EXPECT_KEY = 7; + SONIC_EXPECT_COLON = 8; + SONIC_EXPECT_OBJ_COMMA_OR_END = 9; + SONIC_EXPECT_ARR_COMMA_OR_END = 10; + SONIC_VISIT_FAILED = 11; + SONIC_INVALID_ESCAPED_UTF = 12; + SONIC_INVALID_LITERAL = 13; + SONIC_STACK_OVERFLOW = 14; +) + +var ParsingErrors = []string{ + SONIC_OK : "ok", + SONIC_CONTROL_CHAR : "control chars in string", + SONIC_INVALID_ESCAPED : "invalid escaped chars in string", + SONIC_INVALID_NUM : "invalid number", + SONIC_FLOAT_INF : "float infinity", + SONIC_EOF : "eof", + SONIC_INVALID_CHAR : "invalid chars", + SONIC_EXPECT_KEY : "expect a json key", + SONIC_EXPECT_COLON : "expect a `:`", + SONIC_EXPECT_OBJ_COMMA_OR_END : "expect a `,` or `}`", + SONIC_EXPECT_ARR_COMMA_OR_END : "expect a `,` or `]`", + SONIC_VISIT_FAILED : "failed in json visitor", + SONIC_INVALID_ESCAPED_UTF : "invalid escaped unicodes", + SONIC_INVALID_LITERAL : "invalid literal(true/false/null)", + SONIC_STACK_OVERFLOW : "json is exceeded max depth 4096, cause stack overflow", +} + +func (code ErrorCode) Error() string { + return ParsingErrors[code] +} + +type node struct { + typ uint64 + val uint64 +} + +// should consitent with native/parser.c +type _nospaceBlock struct { + _ [8]byte + _ [8]byte +} + +// should consitent with native/parser.c +type nodeBuf struct { + ncur uintptr + parent int64 + depth uint64 + nstart uintptr + nend uintptr + stat jsonStat +} + +func (self *nodeBuf) init(nodes []node) { + self.ncur = uintptr(unsafe.Pointer(&nodes[0])) + self.nstart = self.ncur + self.nend = self.ncur + uintptr(cap(nodes)) * unsafe.Sizeof(node{}) + self.parent = -1 +} + +// should consitent with native/parser.c +type Parser struct { + Json string + padded []byte + nodes []node + dbuf []byte + backup []node + + options uint64 + // JSON cursor + start uintptr + cur uintptr + end uintptr + _nbk _nospaceBlock + + // node buffer cursor + nbuf nodeBuf + Utf8Inv bool + isEface bool +} + +// only when parse non-empty object/array are needed. +type jsonStat struct { + object uint32 + array uint32 + str uint32 + number uint32 + array_elems uint32 + object_keys uint32 + max_depth uint32 +} + + +var ( + defaultJsonPaddedCap uintptr = 1 << 20 // 1 Mb + defaultNodesCap uintptr = (1 << 20) / unsafe.Sizeof(node{}) // 1 Mb +) + +var parsePool sync.Pool = sync.Pool { + New: func () interface{} { + return &Parser{ + options: 0, + padded: make([]byte, 0, defaultJsonPaddedCap), + nodes: make([]node, defaultNodesCap, defaultNodesCap), + dbuf: make([]byte, types.MaxDigitNums, types.MaxDigitNums), + } + }, +} + +var padding string = "x\"x\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + +func newParser(data string, pos int, opt uint64) *Parser { + p := parsePool.Get().(*Parser) + + /* validate json if needed */ + if (opt & (1 << _F_validate_string)) != 0 && !utf8.ValidateString(data){ + dbuf := utf8.CorrectWith(nil, rt.Str2Mem(data[pos:]), "\ufffd") + dbuf = append(dbuf, padding...) + p.Json = rt.Mem2Str(dbuf[:len(dbuf) - len(padding)]) + p.Utf8Inv = true + p.start = uintptr((*rt.GoString)(unsafe.Pointer(&p.Json)).Ptr) + } else { + p.Json = data + // TODO: prevent too large JSON + p.padded = append(p.padded, data[pos:]...) + p.padded = append(p.padded, padding...) + p.start = uintptr((*rt.GoSlice)(unsafe.Pointer(&p.padded)).Ptr) + } + + p.cur = p.start + p.end = p.cur + uintptr(len(p.Json)) + p.options = opt + p.nbuf.init(p.nodes) + return p +} + + +func (p *Parser) Pos() int { + return int(p.cur - p.start) +} + +func (p *Parser) JsonBytes() []byte { + if p.Utf8Inv { + return (rt.Str2Mem(p.Json)) + } else { + return p.padded + } +} + +var nodeType = rt.UnpackType(reflect.TypeOf(node{})) + +//go:inline +func calMaxNodeCap(jsonSize int) int { + return jsonSize / 2 + 2 +} + +func (p *Parser) parse() ErrorCode { + // when decode into struct, we should decode number as possible + old := p.options + if !p.isEface { + p.options &^= 1 << _F_use_number + } + + // fast path with limited node buffer + err := ErrorCode(native.ParseWithPadding(unsafe.Pointer(p))) + if err != SONIC_VISIT_FAILED { + p.options = old + return err + } + + // check OoB here + offset := p.nbuf.ncur - p.nbuf.nstart + curLen := offset / unsafe.Sizeof(node{}) + if curLen != uintptr(len(p.nodes)) { + panic(fmt.Sprintf("current len: %d, real len: %d cap: %d", curLen, len(p.nodes), cap(p.nodes))) + } + + // node buf is not enough, continue parse + // the maxCap is always meet all valid JSON + maxCap := calMaxNodeCap(len(p.Json)) + slice := rt.GoSlice{ + Ptr: rt.Mallocgc(uintptr(maxCap) * nodeType.Size, nodeType, false), + Len: maxCap, + Cap: maxCap, + } + rt.Memmove(unsafe.Pointer(slice.Ptr), unsafe.Pointer(&p.nodes[0]), offset) + p.backup = p.nodes + p.nodes = *(*[]node)(unsafe.Pointer(&slice)) + + // update node cursor + p.nbuf.nstart = uintptr(unsafe.Pointer(&p.nodes[0])) + p.nbuf.nend = p.nbuf.nstart + uintptr(cap(p.nodes)) * unsafe.Sizeof(node{}) + p.nbuf.ncur = p.nbuf.nstart + offset + + // continue parse json + err = ErrorCode(native.ParseWithPadding(unsafe.Pointer(p))) + p.options = old + return err +} + +func (p *Parser) reset() { + p.options = 0 + p.padded = p.padded[:0] + // nodes is too large here, we will not reset it and use small backup nodes buffer + if p.backup != nil { + p.nodes = p.backup + p.backup = nil + } + p.start = 0 + p.cur = 0 + p.end = 0 + p.Json = "" + p.nbuf = nodeBuf{} + p._nbk = _nospaceBlock{} + p.Utf8Inv = false + p.isEface = false +} + +func (p *Parser) free() { + p.reset() + parsePool.Put(p) +} + +//go:noinline +func (p *Parser) fixError(code ErrorCode) error { + if code == SONIC_OK { + return nil + } + + if p.Pos() == 0 { + code = SONIC_EOF; + } + + pos := p.Pos() - 1 + return error_syntax(pos, p.Json, ParsingErrors[code]) +} + +func Parse(data string, opt uint64) error { + p := newParser(data, 0, opt) + err := p.parse() + p.free() + return err +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go new file mode 100644 index 000000000..3f60a3368 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go @@ -0,0 +1,1278 @@ +package optdec + +import ( + "encoding/json" + "math" + "unsafe" + + "github.com/bytedance/sonic/internal/envs" + "github.com/bytedance/sonic/internal/rt" +) + +type Context struct { + Parser *Parser + efacePool *efacePool + Stack bounedStack + Utf8Inv bool +} + +func (ctx *Context) Options() uint64 { + return ctx.Parser.options +} + +/************************* Stack and Pool Helper *******************/ + +type parentStat struct { + con unsafe.Pointer + remain uint64 +} +type bounedStack struct { + stack []parentStat + index int +} + +func newStack(size int) bounedStack { + return bounedStack{ + stack: make([]parentStat, size + 2), + index: 0, + } +} + +//go:nosplit +func (s *bounedStack) Pop() (unsafe.Pointer, int, bool){ + s.index-- + con := s.stack[s.index].con + remain := s.stack[s.index].remain &^ (uint64(1) << 63) + isObj := (s.stack[s.index].remain & (uint64(1) << 63)) != 0 + s.stack[s.index].con = nil + s.stack[s.index].remain = 0 + return con, int(remain), isObj +} + +//go:nosplit +func (s *bounedStack) Push(p unsafe.Pointer, remain int, isObj bool) { + s.stack[s.index].con = p + s.stack[s.index].remain = uint64(remain) + if isObj { + s.stack[s.index].remain |= (uint64(1) << 63) + } + s.index++ +} + +type efacePool struct{ + t64 rt.T64Pool + tslice rt.TslicePool + tstring rt.TstringPool + efaceSlice rt.SlicePool +} + +func newEfacePool(stat *jsonStat, useNumber bool) *efacePool { + strs := int(stat.str) + nums := 0 + if useNumber { + strs += int(stat.number) + } else { + nums = int(stat.number) + } + + return &efacePool{ + t64: rt.NewT64Pool(nums), + tslice: rt.NewTslicePool(int(stat.array)), + tstring: rt.NewTstringPool(strs), + efaceSlice: rt.NewPool(rt.AnyType, int(stat.array_elems)), + } +} + +func (self *efacePool) GetMap(hint int) unsafe.Pointer { + m := make(map[string]interface{}, hint) + return *(*unsafe.Pointer)(unsafe.Pointer(&m)) +} + +func (self *efacePool) GetSlice(hint int) unsafe.Pointer { + return unsafe.Pointer(self.efaceSlice.GetSlice(hint)) +} + +func (self *efacePool) ConvTSlice(val rt.GoSlice, typ *rt.GoType, dst unsafe.Pointer) { + self.tslice.Conv(val, typ, (*interface{})(dst)) +} + +func (self *efacePool) ConvF64(val float64, dst unsafe.Pointer) { + self.t64.Conv(castU64(val), rt.Float64Type, (*interface{})(dst)) +} + +func (self *efacePool) ConvTstring(val string, dst unsafe.Pointer) { + self.tstring.Conv(val, (*interface{})(dst)) +} + +func (self *efacePool) ConvTnum(val json.Number, dst unsafe.Pointer) { + self.tstring.ConvNum(val, (*interface{})(dst)) +} + +/********************************************************/ + +func canUseFastMap( opts uint64, root *rt.GoType) bool { + return envs.UseFastMap && (opts & (1 << _F_copy_string)) == 0 && (opts & (1 << _F_use_int64)) == 0 && (root == rt.AnyType || root == rt.MapEfaceType || root == rt.SliceEfaceType) +} + +func NewContext(json string, pos int, opts uint64, root *rt.GoType) (Context, error) { + ctx := Context{ + Parser: newParser(json, pos, opts), + } + if root == rt.AnyType || root == rt.MapEfaceType || root == rt.SliceEfaceType { + ctx.Parser.isEface = true + } + + ecode := ctx.Parser.parse() + + if ecode != 0 { + return ctx, ctx.Parser.fixError(ecode) + } + + useNumber := (opts & (1 << _F_use_number )) != 0 + if canUseFastMap(opts, root) { + ctx.efacePool = newEfacePool(&ctx.Parser.nbuf.stat, useNumber) + ctx.Stack = newStack(int(ctx.Parser.nbuf.stat.max_depth)) + } + + return ctx, nil +} + +func (ctx *Context) Delete() { + ctx.Parser.free() + ctx.Parser = nil +} + +type Node struct { + cptr uintptr +} + +func NewNode(cptr uintptr) Node { + return Node{cptr: cptr} +} + +type Dom struct { + cdom uintptr +} + +func (ctx *Context) Root() Node { + root := (uintptr)(((*rt.GoSlice)(unsafe.Pointer(&ctx.Parser.nodes))).Ptr) + return Node{cptr: root} +} + +type Array struct { + cptr uintptr +} + +type Object struct { + cptr uintptr +} + +func (obj Object) Len() int { + cobj := ptrCast(obj.cptr) + return int(uint64(cobj.val) & ConLenMask) +} + +func (arr Array) Len() int { + carr := ptrCast(arr.cptr) + return int(uint64(carr.val) & ConLenMask) +} + +// / Helper functions to eliminate CGO calls +func (val Node) Type() uint8 { + ctype := ptrCast(val.cptr) + return uint8(ctype.typ & TypeMask) +} + +func (val Node) Next() uintptr { + if val.Type() != KObject && val.Type() != KArray { + return PtrOffset(val.cptr, 1) + } + cobj := ptrCast(val.cptr) + offset := int64(uint64(cobj.val) >> ConLenBits) + return PtrOffset(val.cptr, offset) +} + +func (val *Node) next() { + *val = NewNode(val.Next()) +} + +type NodeIter struct { + next uintptr +} + +func NewNodeIter(node Node) NodeIter { + return NodeIter{next: node.cptr} +} + +func (iter *NodeIter) Next() Node { + ret := NewNode(iter.next) + iter.next = PtrOffset(iter.next, 1) + return ret +} + + +func (iter *NodeIter) Peek() Node { + return NewNode(iter.next) +} + +func (val Node) U64() uint64 { + cnum := ptrCast(val.cptr) + return *(*uint64)((unsafe.Pointer)(&(cnum.val))) +} + +func (val Node) I64() int64 { + cnum := ptrCast(val.cptr) + return *(*int64)((unsafe.Pointer)(&(cnum.val))) +} + +func (val Node) IsNull() bool { + return val.Type() == KNull +} + +func (val Node) IsNumber() bool { + return val.Type() & KNumber != 0 +} + +func (val Node) F64() float64 { + cnum := ptrCast(val.cptr) + return *(*float64)((unsafe.Pointer)(&(cnum.val))) +} + +func (val Node) Bool() bool { + return val.Type() == KTrue +} + +func (self Node) AsU64(ctx *Context) (uint64, bool) { + if self.Type() == KUint { + return self.U64(), true + } else if self.Type() == KRawNumber { + num, err := ParseU64(self.Raw(ctx)) + if err != nil { + return 0, false + } + return num, true + } else { + return 0, false + } +} + +func (val *Node) AsObj() (Object, bool) { + var ret Object + if val.Type() != KObject { + return ret, false + } + return Object{ + cptr: val.cptr, + }, true +} + +func (val Node) Obj() Object { + return Object{cptr: val.cptr} +} + +func (val Node) Arr() Array { + return Array{cptr: val.cptr} +} + +func (val *Node) AsArr() (Array, bool) { + var ret Array + if val.Type() != KArray { + return ret, false + } + return Array{ + cptr: val.cptr, + }, true +} + +func (self Node) AsI64(ctx *Context) (int64, bool) { + typ := self.Type() + if typ == KUint && self.U64() <= math.MaxInt64 { + return int64(self.U64()), true + } else if typ == KSint { + return self.I64(), true + } else if typ == KRawNumber { + val, err := self.Number(ctx).Int64() + if err != nil { + return 0, false + } + return val, true + } else { + return 0, false + } +} + +/********* Parse Node String into Value ***************/ + +func (val Node) ParseI64(ctx *Context) (int64, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return 0, false + } + + if s == "null" { + return 0, true + } + + i, err := ParseI64(s) + if err != nil { + return 0, false + } + return i, true +} + +func (val Node) ParseBool(ctx *Context) (bool, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return false, false + } + + if s == "null" { + return false, true + } + + b, err := ParseBool(s) + if err != nil { + return false, false + } + return b, true +} + +func (val Node) ParseU64(ctx *Context) (uint64, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return 0, false + } + + if s == "null" { + return 0, true + } + + i, err := ParseU64(s) + if err != nil { + return 0, false + } + return i, true +} + +func (val Node) ParseF64(ctx *Context) (float64, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return 0, false + } + + if s == "null" { + return 0, true + } + + i, err := ParseF64(s) + if err != nil { + return 0, false + } + return i, true +} + +func (val Node) ParseString(ctx *Context) (string, bool) { + // shoud not use AsStrRef + s, ok := val.AsStr(ctx) + if !ok { + return "", false + } + + if s == "null" { + return "", true + } + + s, err := Unquote(s) + if err != nil { + return "", false + } + return s, true +} + + +func (val Node) ParseNumber(ctx *Context) (json.Number, bool) { + // shoud not use AsStrRef + s, ok := val.AsStr(ctx) + if !ok { + return json.Number(""), false + } + + if s == "null" { + return json.Number(""), true + } + + end, ok := SkipNumberFast(s, 0) + // has error or trailing chars + if !ok || end != len(s) { + return json.Number(""), false + } + return json.Number(s), true +} + + + +func (val Node) AsF64(ctx *Context) (float64, bool) { + switch val.Type() { + case KUint: return float64(val.U64()), true + case KSint: return float64(val.I64()), true + case KReal: return float64(val.F64()), true + case KRawNumber: f, err := val.Number(ctx).Float64(); return f, err == nil + default: return 0, false + } +} + +func (val Node) AsBool() (bool, bool) { + switch val.Type() { + case KTrue: return true, true + case KFalse: return false, true + default: return false, false + } +} + +func (val Node) AsStr(ctx *Context) (string, bool) { + switch val.Type() { + case KStringCommon: + s := val.StringRef(ctx) + if (ctx.Options() & (1 << _F_copy_string) == 0) { + return s, true + } + return string(rt.Str2Mem(s)), true + case KStringEscaped: + return val.StringCopyEsc(ctx), true + default: return "", false + } +} + +func (val Node) AsStrRef(ctx *Context) (string, bool) { + switch val.Type() { + case KStringEscaped: + node := ptrCast(val.cptr) + offset := val.Position() + len := int(node.val) + return rt.Mem2Str(ctx.Parser.JsonBytes()[offset : offset + len]), true + case KStringCommon: + return val.StringRef(ctx), true + default: + return "", false + } +} + +func (val Node) AsBytesRef(ctx *Context) ([]byte, bool) { + switch val.Type() { + case KStringEscaped: + node := ptrCast(val.cptr) + offset := val.Position() + len := int(node.val) + return ctx.Parser.JsonBytes()[offset : offset + len], true + case KStringCommon: + return rt.Str2Mem(val.StringRef(ctx)), true + default: + return nil, false + } +} + +func (val Node) AsStringText(ctx *Context) ([]byte, bool) { + if !val.IsStr() { + return nil, false + } + + // clone to new bytes + s, b := val.AsStrRef(ctx) + return []byte(s), b +} + +func (val Node) IsStr() bool { + return (val.Type() == KStringCommon) || (val.Type() == KStringEscaped) +} + +func (val Node) IsRawNumber() bool { + return val.Type() == KRawNumber +} + +func (val Node) Number(ctx *Context) json.Number { + return json.Number(val.Raw(ctx)) +} + +func (val Node) Raw(ctx *Context) string { + node := ptrCast(val.cptr) + len := int(node.val) + offset := val.Position() + return ctx.Parser.Json[offset:int(offset+len)] +} + +func (val Node) Position() int { + node := ptrCast(val.cptr) + return int(node.typ >> PosBits) +} + +func (val Node) AsNumber(ctx *Context) (json.Number, bool) { + // parse JSON string as number + if val.IsStr() { + s, _ := val.AsStr(ctx) + if !ValidNumberFast(s) { + return "", false + } else { + return json.Number(s), true + } + } + + return val.NonstrAsNumber(ctx) +} + +func (val Node) NonstrAsNumber(ctx *Context) (json.Number, bool) { + // deal with raw number + if val.IsRawNumber() { + return val.Number(ctx), true + } + + // deal with parse number + if !val.IsNumber() { + return json.Number(""), false + } + + start := val.Position() + end, ok := SkipNumberFast(ctx.Parser.Json, start) + if !ok { + return "", false + } + return json.Number(ctx.Parser.Json[start:end]), true +} + +func (val Node) AsRaw(ctx *Context) string { + // fast path for unescaped strings + switch val.Type() { + case KNull: + return "null" + case KTrue: + return "true" + case KFalse: + return "false" + case KStringCommon: + node := ptrCast(val.cptr) + len := int(node.val) + offset := val.Position() + // add start abd end quote + ref := rt.Str2Mem(ctx.Parser.Json)[offset-1 : offset+len+1] + return rt.Mem2Str(ref) + case KRawNumber: fallthrough + case KRaw: return val.Raw(ctx) + case KStringEscaped: + raw, _ := SkipOneFast(ctx.Parser.Json, val.Position() - 1) + return raw + default: + raw, err := SkipOneFast(ctx.Parser.Json, val.Position()) + if err != nil { + break + } + return raw + } + panic("should always be valid json here") +} + +// reference from the input JSON as possible +func (val Node) StringRef(ctx *Context) string { + return val.Raw(ctx) +} + +//go:nocheckptr +func ptrCast(p uintptr) *node { + return (*node)(unsafe.Pointer(p)) +} + +func (val Node) StringCopyEsc(ctx *Context) string { + // check whether there are in padded + node := ptrCast(val.cptr) + len := int(node.val) + offset := val.Position() + return string(ctx.Parser.JsonBytes()[offset : offset + len]) +} + +func (val Node) Object() Object { + return Object{cptr: val.cptr} +} + +func (val Node) Array() Array { + return Array{cptr: val.cptr} +} + +func (val *Array) Children() uintptr { + return PtrOffset(val.cptr, 1) +} + +func (val *Object) Children() uintptr { + return PtrOffset(val.cptr, 1) +} + +func (val *Node) Equal(ctx *Context, lhs string) bool { + // check whether escaped + cstr := ptrCast(val.cptr) + offset := int(val.Position()) + len := int(cstr.val) + return lhs == ctx.Parser.Json[offset:offset+len] +} + +func (node *Node) AsMapEface(ctx *Context, vp unsafe.Pointer) error { + if node.IsNull() { + return nil + } + + obj, ok := node.AsObj() + if !ok { + return newUnmatched(node.Position(), rt.MapEfaceType) + } + + var err, gerr error + size := obj.Len() + + var m map[string]interface{} + if *(*unsafe.Pointer)(vp) == nil { + if ctx.efacePool != nil { + p := ctx.efacePool.GetMap(size) + m = *(*map[string]interface{})(unsafe.Pointer(&p)) + } else { + m = make(map[string]interface{}, size) + } + } else { + m = *(*map[string]interface{})(vp) + } + + next := obj.Children() + for i := 0; i < size; i++ { + knode := NewNode(next) + key, _ := knode.AsStr(ctx) + val := NewNode(PtrOffset(next, 1)) + m[key], err = val.AsEface(ctx) + next = val.cptr + if gerr == nil && err != nil { + gerr = err + } + } + + *(*map[string]interface{})(vp) = m + return gerr +} + +func (node *Node) AsMapString(ctx *Context, vp unsafe.Pointer) error { + obj, ok := node.AsObj() + if !ok { + return newUnmatched(node.Position(), rt.MapStringType) + } + + size := obj.Len() + + var m map[string]string + if *(*unsafe.Pointer)(vp) == nil { + m = make(map[string]string, size) + } else { + m = *(*map[string]string)(vp) + } + + var gerr error + next := obj.Children() + for i := 0; i < size; i++ { + knode := NewNode(next) + key, _ := knode.AsStr(ctx) + val := NewNode(PtrOffset(next, 1)) + m[key], ok = val.AsStr(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.StringType) + } + next = val.Next() + } else { + next = PtrOffset(val.cptr, 1) + } + } + + *(*map[string]string)(vp) = m + return gerr +} + +func (node *Node) AsSliceEface(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceEfaceType) + } + + size := arr.Len() + var s []interface{} + if size != 0 && ctx.efacePool != nil { + slice := rt.GoSlice { + Ptr: ctx.efacePool.GetSlice(size), + Len: size, + Cap: size, + } + *(*rt.GoSlice)(unsafe.Pointer(&s)) = slice + } else { + s = *(*[]interface{})((unsafe.Pointer)(rt.MakeSlice(vp, rt.AnyType, size))) + } + + *node = NewNode(arr.Children()) + + var err, gerr error + for i := 0; i < size; i++ { + s[i], err = node.AsEface(ctx) + if gerr == nil && err != nil { + gerr = err + } + } + + *(*[]interface{})(vp) = s + return nil +} + +func (node *Node) AsSliceI32(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceI32Type) + } + + size := arr.Len() + s := *(*[]int32)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Int32Type, size))) + next := arr.Children() + + var gerr error + for i := 0; i < size; i++ { + val := NewNode(next) + ret, ok := val.AsI64(ctx) + if !ok || ret > math.MaxInt32 || ret < math.MinInt32 { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.Int32Type) + } + next = val.Next() + } else { + s[i] = int32(ret) + next = PtrOffset(val.cptr, 1) + } + } + + *(*[]int32)(vp) = s + return gerr +} + +func (node *Node) AsSliceI64(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceI64Type) + } + + size := arr.Len() + s := *(*[]int64)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Int64Type, size))) + next := arr.Children() + + var gerr error + for i := 0; i < size; i++ { + val := NewNode(next) + + ret, ok := val.AsI64(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.Int64Type) + } + next = val.Next() + } else { + s[i] = ret + next = PtrOffset(val.cptr, 1) + } + } + + *(*[]int64)(vp) = s + return gerr +} + +func (node *Node) AsSliceU32(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceU32Type) + } + + size := arr.Len() + next := arr.Children() + s := *(*[]uint32)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Uint32Type, size))) + + var gerr error + for i := 0; i < size; i++ { + val := NewNode(next) + ret, ok := val.AsU64(ctx) + if !ok || ret > math.MaxUint32 { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.Uint32Type) + } + next = val.Next() + } else { + s[i] = uint32(ret) + next = PtrOffset(val.cptr, 1) + } + } + + *(*[]uint32)(vp) = s + return gerr +} + +func (node *Node) AsSliceU64(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceU64Type) + } + + size := arr.Len() + next := arr.Children() + + s := *(*[]uint64)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Uint64Type, size))) + var gerr error + for i := 0; i < size; i++ { + val := NewNode(next) + ret, ok := val.AsU64(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.Uint64Type) + } + next = val.Next() + } else { + s[i] = ret + next = PtrOffset(val.cptr, 1) + } + } + + *(*[]uint64)(vp) = s + return gerr +} + +func (node *Node) AsSliceString(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceStringType) + } + + size := arr.Len() + next := arr.Children() + s := *(*[]string)((unsafe.Pointer)(rt.MakeSlice(vp, rt.StringType, size))) + + var gerr error + for i := 0; i < size; i++ { + val := NewNode(next) + ret, ok := val.AsStr(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.StringType) + } + next = val.Next() + } else { + s[i] = ret + next = PtrOffset(val.cptr, 1) + } + } + + *(*[]string)(vp) = s + return gerr +} + +func (node *Node) AsSliceBytes(ctx *Context) ([]byte, error) { + b, ok := node.AsBytesRef(ctx) + if !ok { + return nil, newUnmatched(node.Position(), rt.BytesType) + } + + b64, err := rt.DecodeBase64(b) + if err != nil { + return nil, newUnmatched(node.Position(), rt.BytesType) + } + return b64, nil +} + +// AsEface will always ok, because we have parse in native. +func (node *Node) AsEface(ctx *Context) (interface{}, error) { + if ctx.efacePool != nil { + iter := NewNodeIter(*node) + v := AsEfaceFast(&iter, ctx) + *node = iter.Peek() + return v, nil + } else { + return node.AsEfaceFallback(ctx) + } +} + +func parseSingleNode(node Node, ctx *Context) interface{} { + var v interface{} + switch node.Type() { + case KObject: v = map[string]interface{}{} + case KArray: v = []interface{}{} + case KStringCommon: v = node.StringRef(ctx) + case KStringEscaped: v = node.StringCopyEsc(ctx) + case KTrue: v = true + case KFalse: v = false + case KNull: v = nil + case KUint: v = float64(node.U64()) + case KSint: v = float64(node.I64()) + case KReal: v = float64(node.F64()) + case KRawNumber: v = node.Number(ctx) + default: panic("unreachable for as eface") + } + return v +} + +func castU64(val float64) uint64 { + return *((*uint64)(unsafe.Pointer((&val)))) +} + +func AsEfaceFast(iter *NodeIter, ctx *Context) interface{} { + var mp, sp, parent unsafe.Pointer // current container pointer + var node Node + var size int + var isObj bool + var slice rt.GoSlice + var val unsafe.Pointer + var vt **rt.GoType + var vp *unsafe.Pointer + var rootM unsafe.Pointer + var rootS rt.GoSlice + var root interface{} + var key string + + node = iter.Next() + + switch node.Type() { + case KObject: + size = node.Object().Len() + if size != 0 { + ctx.Stack.Push(nil, 0, true) + mp = ctx.efacePool.GetMap(size) + rootM = mp + isObj = true + goto _object_key + } else { + return rt.GoEface { + Type: rt.MapEfaceType, + Value: ctx.efacePool.GetMap(0), + }.Pack() + } + case KArray: + size = node.Array().Len() + if size != 0 { + ctx.Stack.Push(nil, 0, false) + sp = ctx.efacePool.GetSlice(size) + slice = rt.GoSlice { + Ptr: sp, + Len: size, + Cap: size, + } + rootS = slice + isObj = false + val = sp + goto _arr_val; + } else { + ctx.efacePool.ConvTSlice(rt.EmptySlice, rt.SliceEfaceType, unsafe.Pointer(&root)) + } + case KStringCommon: ctx.efacePool.ConvTstring(node.StringRef(ctx), unsafe.Pointer(&root)) + case KStringEscaped: ctx.efacePool.ConvTstring(node.StringCopyEsc(ctx), unsafe.Pointer(&root)) + case KTrue: root = true + case KFalse: root = false + case KNull: root = nil + case KUint: ctx.efacePool.ConvF64(float64(node.U64()), unsafe.Pointer(&root)) + case KSint: ctx.efacePool.ConvF64(float64(node.I64()), unsafe.Pointer(&root)) + case KReal: ctx.efacePool.ConvF64(node.F64(), unsafe.Pointer(&root)) + case KRawNumber: ctx.efacePool.ConvTnum(node.Number(ctx), unsafe.Pointer(&root)) + default: panic("unreachable for as eface") + } + return root + +_object_key: + node = iter.Next() + if node.Type() == KStringCommon { + key = node.StringRef(ctx) + } else { + key = node.StringCopyEsc(ctx) + } + + // interface{} slot in map bucket + val = rt.Mapassign_faststr(rt.MapEfaceMapType, mp, key) + vt = &(*rt.GoEface)(val).Type + vp = &(*rt.GoEface)(val).Value + + // parse value node + node = iter.Next() + switch node.Type() { + case KObject: + newSize := node.Object().Len() + newMp := ctx.efacePool.GetMap(newSize) + *vt = rt.MapEfaceType + *vp = newMp + remain := size - 1 + isObj = true + if newSize != 0 { + if remain > 0 { + ctx.Stack.Push(mp, remain, true) + } + mp = newMp + size = newSize + goto _object_key; + } + case KArray: + newSize := node.Array().Len() + if newSize == 0 { + ctx.efacePool.ConvTSlice(rt.EmptySlice, rt.SliceEfaceType, val) + break; + } + + newSp := ctx.efacePool.GetSlice(newSize) + // pack to []interface{} + ctx.efacePool.ConvTSlice(rt.GoSlice{ + Ptr: newSp, + Len: newSize, + Cap: newSize, + }, rt.SliceEfaceType, val) + remain := size - 1 + if remain > 0 { + ctx.Stack.Push(mp, remain, true) + } + val = newSp + isObj = false + size = newSize + goto _arr_val; + case KStringCommon: + ctx.efacePool.ConvTstring(node.StringRef(ctx), val) + case KStringEscaped: + ctx.efacePool.ConvTstring(node.StringCopyEsc(ctx), val) + case KTrue: + rt.ConvTBool(true, (*interface{})(val)) + case KFalse: + rt.ConvTBool(false, (*interface{})(val)) + case KNull: /* skip */ + case KUint: + ctx.efacePool.ConvF64(float64(node.U64()), val) + case KSint: + ctx.efacePool.ConvF64(float64(node.I64()), val) + case KReal: + ctx.efacePool.ConvF64(node.F64(), val) + case KRawNumber: + ctx.efacePool.ConvTnum(node.Number(ctx), val) + default: + panic("unreachable for as eface") + } + + // check size + size -= 1 + if size != 0 { + goto _object_key; + } + + parent, size, isObj = ctx.Stack.Pop() + + // parent is empty + if parent == nil { + if isObj { + return rt.GoEface { + Type: rt.MapEfaceType, + Value: rootM, + }.Pack() + } else { + ctx.efacePool.ConvTSlice(rootS, rt.SliceEfaceType, (unsafe.Pointer)(&root)) + return root + } + } + + // continue to parse parent + if isObj { + mp = parent + goto _object_key; + } else { + val = rt.PtrAdd(parent, rt.AnyType.Size) + goto _arr_val; + } + +_arr_val: + // interface{} slot in slice + vt = &(*rt.GoEface)(val).Type + vp = &(*rt.GoEface)(val).Value + + // parse value node + node = iter.Next() + switch node.Type() { + case KObject: + newSize := node.Object().Len() + newMp := ctx.efacePool.GetMap(newSize) + *vt = rt.MapEfaceType + *vp = newMp + remain := size - 1 + if newSize != 0 { + // push next array elem into stack + if remain > 0 { + ctx.Stack.Push(val, remain, false) + } + mp = newMp + size = newSize + isObj = true + goto _object_key; + } + case KArray: + newSize := node.Array().Len() + if newSize == 0 { + ctx.efacePool.ConvTSlice(rt.EmptySlice, rt.SliceEfaceType, val) + break; + } + + newSp := ctx.efacePool.GetSlice(newSize) + // pack to []interface{} + ctx.efacePool.ConvTSlice(rt.GoSlice { + Ptr: newSp, + Len: newSize, + Cap: newSize, + }, rt.SliceEfaceType, val) + + remain := size - 1 + if remain > 0 { + ctx.Stack.Push(val, remain, false) + } + + val = newSp + isObj = false + size = newSize + goto _arr_val; + case KStringCommon: + ctx.efacePool.ConvTstring(node.StringRef(ctx), val) + case KStringEscaped: + ctx.efacePool.ConvTstring(node.StringCopyEsc(ctx), val) + case KTrue: + rt.ConvTBool(true, (*interface{})(val)) + case KFalse: + rt.ConvTBool(false, (*interface{})(val)) + case KNull: /* skip */ + case KUint: + ctx.efacePool.ConvF64(float64(node.U64()), val) + case KSint: + ctx.efacePool.ConvF64(float64(node.I64()), val) + case KReal: + ctx.efacePool.ConvF64(node.F64(), val) + case KRawNumber: + ctx.efacePool.ConvTnum(node.Number(ctx), val) + default: panic("unreachable for as eface") + } + + // check size + size -= 1 + if size != 0 { + val = rt.PtrAdd(val, rt.AnyType.Size) + goto _arr_val; + } + + + parent, size, isObj = ctx.Stack.Pop() + + // parent is empty + if parent == nil { + if isObj { + return rt.GoEface { + Type: rt.MapEfaceType, + Value: rootM, + }.Pack() + } else { + ctx.efacePool.ConvTSlice(rootS, rt.SliceEfaceType, unsafe.Pointer(&root)) + return root + } + } + + // continue to parse parent + if isObj { + mp = parent + goto _object_key; + } else { + val = rt.PtrAdd(parent, rt.AnyType.Size) + goto _arr_val; + } +} + +func (node *Node) AsEfaceFallback(ctx *Context) (interface{}, error) { + switch node.Type() { + case KObject: + obj := node.Object() + size := obj.Len() + m := make(map[string]interface{}, size) + *node = NewNode(obj.Children()) + var gerr, err error + for i := 0; i < size; i++ { + key, _ := node.AsStr(ctx) + *node = NewNode(PtrOffset(node.cptr, 1)) + m[key], err = node.AsEfaceFallback(ctx) + if gerr == nil && err != nil { + gerr = err + } + } + return m, gerr + case KArray: + arr := node.Array() + size := arr.Len() + a := make([]interface{}, size) + *node = NewNode(arr.Children()) + var gerr, err error + for i := 0; i < size; i++ { + a[i], err = node.AsEfaceFallback(ctx) + if gerr == nil && err != nil { + gerr = err + } + } + return a, gerr + case KStringCommon: + str, _ := node.AsStr(ctx) + *node = NewNode(PtrOffset(node.cptr, 1)) + return str, nil + case KStringEscaped: + str := node.StringCopyEsc(ctx) + *node = NewNode(PtrOffset(node.cptr, 1)) + return str, nil + case KTrue: + *node = NewNode(PtrOffset(node.cptr, 1)) + return true, nil + case KFalse: + *node = NewNode(PtrOffset(node.cptr, 1)) + return false, nil + case KNull: + *node = NewNode(PtrOffset(node.cptr, 1)) + return nil, nil + default: + // use float64 + if ctx.Parser.options & (1 << _F_use_number) != 0 { + num, ok := node.AsNumber(ctx) + if !ok { + // skip the unmacthed type + *node = NewNode(node.Next()) + return nil, newUnmatched(node.Position(), rt.JsonNumberType) + } else { + *node = NewNode(PtrOffset(node.cptr, 1)) + return num, nil + } + } else if ctx.Parser.options & (1 << _F_use_int64) != 0 { + // first try int64 + i, ok := node.AsI64(ctx) + if ok { + *node = NewNode(PtrOffset(node.cptr, 1)) + return i, nil + } + + // is not integer, then use float64 + f, ok := node.AsF64(ctx) + if ok { + *node = NewNode(PtrOffset(node.cptr, 1)) + return f, nil + } + + // skip the unmacthed type + *node = NewNode(node.Next()) + return nil, newUnmatched(node.Position(), rt.Int64Type) + } else { + num, ok := node.AsF64(ctx) + if !ok { + // skip the unmacthed type + *node = NewNode(node.Next()) + return nil, newUnmatched(node.Position(), rt.Float64Type) + } else { + *node = NewNode(PtrOffset(node.cptr, 1)) + return num, nil + } + } + } +} + +//go:nosplit +func PtrOffset(ptr uintptr, off int64) uintptr { + return uintptr(int64(ptr) + off * int64(unsafe.Sizeof(node{}))) +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go new file mode 100644 index 000000000..a94e422b3 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go @@ -0,0 +1,224 @@ +package optdec + +import ( + "reflect" + "unsafe" + + "github.com/bytedance/sonic/internal/rt" +) + +type sliceDecoder struct { + elemType *rt.GoType + elemDec decFunc + typ reflect.Type +} + +var ( + emptyPtr = &struct{}{} +) + +func (d *sliceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + arr, ok := node.AsArr() + if !ok { + return error_mismatch(node, ctx, d.typ) + } + + slice := rt.MakeSlice(vp, d.elemType, arr.Len()) + elems := slice.Ptr + next := arr.Children() + + var gerr error + for i := 0; i < arr.Len(); i++ { + val := NewNode(next) + elem := unsafe.Pointer(uintptr(elems) + uintptr(i)*d.elemType.Size) + err := d.elemDec.FromDom(elem, val, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = val.Next() + } + + *(*rt.GoSlice)(vp) = *slice + return gerr +} + +type arrayDecoder struct { + len int + elemType *rt.GoType + elemDec decFunc + typ reflect.Type +} + +//go:nocheckptr +func (d *arrayDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + arr, ok := node.AsArr() + if !ok { + return error_mismatch(node, ctx, d.typ) + } + + next := arr.Children() + i := 0 + + var gerr error + for ; i < d.len && i < arr.Len(); i++ { + elem := unsafe.Pointer(uintptr(vp) + uintptr(i)*d.elemType.Size) + val := NewNode(next) + err := d.elemDec.FromDom(elem, val, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = val.Next() + } + + /* zero rest of array */ + ptr := unsafe.Pointer(uintptr(vp) + uintptr(i)*d.elemType.Size) + n := uintptr(d.len-i) * d.elemType.Size + rt.ClearMemory(d.elemType, ptr, n) + return gerr +} + +type sliceEfaceDecoder struct { +} + +func (d *sliceEfaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceEface(ctx, vp) +} + +type sliceI32Decoder struct { +} + +func (d *sliceI32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceI32(ctx, vp) +} + +type sliceI64Decoder struct { +} + +func (d *sliceI64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceI64(ctx, vp) +} + +type sliceU32Decoder struct { +} + +func (d *sliceU32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceU32(ctx, vp) +} + +type sliceU64Decoder struct { +} + +func (d *sliceU64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceU64(ctx, vp) +} + +type sliceStringDecoder struct { +} + +func (d *sliceStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceString(ctx, vp) +} + +type sliceBytesDecoder struct { +} + +func (d *sliceBytesDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + s, err := node.AsSliceBytes(ctx) + if err != nil { + return err + } + + *(*[]byte)(vp) = s + return nil +} + +type sliceBytesUnmarshalerDecoder struct { + elemType *rt.GoType + elemDec decFunc + typ reflect.Type +} + +func (d *sliceBytesUnmarshalerDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + /* parse JSON string into `[]byte` */ + if node.IsStr() { + slice, err := node.AsSliceBytes(ctx) + if err != nil { + return err + } + *(*[]byte)(vp) = slice + return nil + } + + /* parse JSON array into `[]byte` */ + arr, ok := node.AsArr() + if !ok { + return error_mismatch(node, ctx, d.typ) + } + + slice := rt.MakeSlice(vp, d.elemType, arr.Len()) + elems := slice.Ptr + + var gerr error + next := arr.Children() + for i := 0; i < arr.Len(); i++ { + child := NewNode(next) + elem := unsafe.Pointer(uintptr(elems) + uintptr(i)*d.elemType.Size) + err := d.elemDec.FromDom(elem, child, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = child.Next() + } + + *(*rt.GoSlice)(vp) = *slice + return gerr +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go new file mode 100644 index 000000000..5af8c97e2 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go @@ -0,0 +1,360 @@ +package optdec + +import ( + "encoding/json" + "math" + "unsafe" + + "github.com/bytedance/sonic/internal/rt" +) + +type ptrStrDecoder struct { + typ *rt.GoType + deref decFunc +} + +// Pointer Value is allocated in the Caller +func (d *ptrStrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + if *(*unsafe.Pointer)(vp) == nil { + *(*unsafe.Pointer)(vp) = rt.Mallocgc(d.typ.Size, d.typ, true) + } + + return d.deref.FromDom(*(*unsafe.Pointer)(vp), node, ctx) +} + +type boolStringDecoder struct { +} + +func (d *boolStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + return nil + } + + b, err := ParseBool(s) + if err != nil { + return error_mismatch(node, ctx, boolType) + } + + *(*bool)(vp) = b + return nil +} + +func parseI64(node Node, ctx *context) (int64, error, bool) { + if node.IsNull() { + return 0, nil, true + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return 0, error_mismatch(node, ctx, stringType), false + } + + if s == "null" { + return 0, nil, true + } + + ret, err := ParseI64(s) + return ret, err, false +} + +type i8StringDecoder struct{} + +func (d *i8StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseI64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxInt8 || ret < math.MinInt8 { + return error_mismatch(node, ctx, int8Type) + } + + *(*int8)(vp) = int8(ret) + return nil +} + +type i16StringDecoder struct{} + +func (d *i16StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseI64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxInt16 || ret < math.MinInt16 { + return error_mismatch(node, ctx, int16Type) + } + + *(*int16)(vp) = int16(ret) + return nil +} + +type i32StringDecoder struct{} + +func (d *i32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseI64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxInt32 || ret < math.MinInt32 { + return error_mismatch(node, ctx, int32Type) + } + + *(*int32)(vp) = int32(ret) + return nil +} + +type i64StringDecoder struct{} + +func (d *i64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseI64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + *(*int64)(vp) = int64(ret) + return nil +} + +func parseU64(node Node, ctx *context) (uint64, error, bool) { + if node.IsNull() { + return 0, nil, true + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return 0, error_mismatch(node, ctx, stringType), false + } + + if s == "null" { + return 0, nil, true + } + + ret, err := ParseU64(s) + return ret, err, false +} + +type u8StringDecoder struct{} + +func (d *u8StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseU64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxUint8 { + return error_mismatch(node, ctx, uint8Type) + } + + *(*uint8)(vp) = uint8(ret) + return nil +} + +type u16StringDecoder struct{} + +func (d *u16StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseU64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxUint16 { + return error_mismatch(node, ctx, uint16Type) + } + + *(*uint16)(vp) = uint16(ret) + return nil +} + +type u32StringDecoder struct{} + +func (d *u32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseU64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxUint32 { + return error_mismatch(node, ctx, uint32Type) + } + + *(*uint32)(vp) = uint32(ret) + return nil +} + + +type u64StringDecoder struct{} + +func (d *u64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseU64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + *(*uint64)(vp) = uint64(ret) + return nil +} + +type f32StringDecoder struct{} + +func (d *f32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + return nil + } + + ret, err := ParseF64(s) + if err != nil || ret > math.MaxFloat32 || ret < -math.MaxFloat32 { + return error_mismatch(node, ctx, float32Type) + } + + *(*float32)(vp) = float32(ret) + return nil +} + +type f64StringDecoder struct{} + +func (d *f64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + return nil + } + + ret, err := ParseF64(s) + if err != nil { + return error_mismatch(node, ctx, float64Type) + } + + *(*float64)(vp) = float64(ret) + return nil +} + +/* parse string field with string options */ +type strStringDecoder struct{} + +func (d *strStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + return nil + } + + s, err := Unquote(s) + if err != nil { + return error_mismatch(node, ctx, stringType) + } + + *(*string)(vp) = s + return nil +} + +type numberStringDecoder struct{} + +func (d *numberStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + return nil + } + + num, ok := node.ParseNumber(ctx) + if !ok { + return error_mismatch(node, ctx, jsonNumberType) + } + + end, ok := SkipNumberFast(s, 0) + // has error or trailing chars + if !ok || end != len(s) { + return error_mismatch(node, ctx, jsonNumberType) + } + + *(*json.Number)(vp) = json.Number(num) + return nil +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go new file mode 100644 index 000000000..bce2758f1 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go @@ -0,0 +1,61 @@ +package optdec + +import ( + "reflect" + "unsafe" + + caching "github.com/bytedance/sonic/internal/optcaching" + "github.com/bytedance/sonic/internal/resolver" +) + +type fieldEntry struct { + resolver.FieldMeta + fieldDec decFunc +} + +type structDecoder struct { + fieldMap caching.FieldLookup + fields []fieldEntry + structName string + typ reflect.Type +} + +func (d *structDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + var gerr error + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.typ) + } + + next := obj.Children() + for i := 0; i < obj.Len(); i++ { + key, _ := NewNode(next).AsStrRef(ctx) + val := NewNode(PtrOffset(next, 1)) + next = val.Next() + + // find field idx + idx := d.fieldMap.Get(key) + if idx == -1 { + if Options(ctx.Options())&OptionDisableUnknown != 0 { + return error_field(key) + } + continue + } + + offset := d.fields[idx].Path[0].Size + elem := unsafe.Pointer(uintptr(vp) + offset) + err := d.fields[idx].fieldDec.FromDom(elem, val, ctx) + + // deal with mismatch type errors + if gerr == nil && err != nil { + // TODO: better error info + gerr = err + } + } + return gerr +} + diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go new file mode 100644 index 000000000..fe1433eec --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go @@ -0,0 +1,60 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package optdec + +import ( + "encoding" + "encoding/base64" + "encoding/json" + "reflect" + "unsafe" + + "github.com/bytedance/sonic/internal/rt" +) + +var ( + boolType = reflect.TypeOf(bool(false)) + byteType = reflect.TypeOf(byte(0)) + intType = reflect.TypeOf(int(0)) + int8Type = reflect.TypeOf(int8(0)) + int16Type = reflect.TypeOf(int16(0)) + int32Type = reflect.TypeOf(int32(0)) + int64Type = reflect.TypeOf(int64(0)) + uintType = reflect.TypeOf(uint(0)) + uint8Type = reflect.TypeOf(uint8(0)) + uint16Type = reflect.TypeOf(uint16(0)) + uint32Type = reflect.TypeOf(uint32(0)) + uint64Type = reflect.TypeOf(uint64(0)) + float32Type = reflect.TypeOf(float32(0)) + float64Type = reflect.TypeOf(float64(0)) + stringType = reflect.TypeOf("") + bytesType = reflect.TypeOf([]byte(nil)) + jsonNumberType = reflect.TypeOf(json.Number("")) + base64CorruptInputError = reflect.TypeOf(base64.CorruptInputError(0)) + anyType = rt.UnpackType(reflect.TypeOf((*interface{})(nil)).Elem()) +) + +var ( + errorType = reflect.TypeOf((*error)(nil)).Elem() + jsonUnmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() + encodingTextUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() +) + +func rtype(t reflect.Type) (*rt.GoItab, *rt.GoType) { + p := (*rt.GoIface)(unsafe.Pointer(&t)) + return p.Itab, (*rt.GoType)(p.Value) +} |