diff options
Diffstat (limited to 'vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go')
-rw-r--r-- | vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go | 1278 |
1 files changed, 0 insertions, 1278 deletions
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go deleted file mode 100644 index b23901e38..000000000 --- a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go +++ /dev/null @@ -1,1278 +0,0 @@ -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) { - // should 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) { - // should 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{}))) -} |