diff --git a/Makefile b/Makefile index 9f68367..75327d4 100644 --- a/Makefile +++ b/Makefile @@ -26,3 +26,7 @@ golangci-lint: | $(BIN_DIR) GOBIN=$(BIN_DIR) go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.36.0; \ rm -rf $$GOLANGCI_LINT_TMP_DIR; \ } + +.PHONY: generate +generate: + go generate ./internal/... diff --git a/encode.go b/encode.go index cb52b07..7f22b25 100644 --- a/encode.go +++ b/encode.go @@ -12,6 +12,8 @@ import ( "strings" "sync" "unsafe" + + _ "github.com/goccy/go-json/internal/encoder/vm" ) // An Encoder writes JSON values to an output stream. diff --git a/cmd/generator/main.go b/internal/cmd/generator/main.go similarity index 74% rename from cmd/generator/main.go rename to internal/cmd/generator/main.go index 1ef7948..85fdadc 100644 --- a/cmd/generator/main.go +++ b/internal/cmd/generator/main.go @@ -66,18 +66,18 @@ func createOpType(op, code string) opType { } func _main() error { - tmpl, err := template.New("").Parse(`// Code generated by cmd/generator. DO NOT EDIT! -package json + tmpl, err := template.New("").Parse(`// Code generated by internal/cmd/generator. DO NOT EDIT! +package encoder import ( "strings" ) -type codeType int +type CodeType int const ( {{- range $index, $type := .CodeTypes }} - code{{ $type }} codeType = {{ $index }} + Code{{ $type }} CodeType = {{ $index }} {{- end }} ) @@ -87,92 +87,86 @@ var opTypeStrings = [{{ .OpLen }}]string{ {{- end }} } -type opType int +type OpType int const ( {{- range $index, $type := .OpTypes }} - op{{ $type.Op }} opType = {{ $index }} + Op{{ $type.Op }} OpType = {{ $index }} {{- end }} ) -func (t opType) String() string { +func (t OpType) String() string { if int(t) >= {{ .OpLen }} { return "" } return opTypeStrings[int(t)] } -func (t opType) codeType() codeType { +func (t OpType) CodeType() CodeType { if strings.Contains(t.String(), "Struct") { if strings.Contains(t.String(), "End") { - return codeStructEnd + return CodeStructEnd } - return codeStructField + return CodeStructField } - if t.String() == "Array" || t.String() == "ArrayPtr" { - return codeArrayHead - } - if strings.Contains(t.String(), "ArrayElem") { - return codeArrayElem - } - if t.String() == "Slice" || t.String() == "SlicePtr" { - return codeSliceHead - } - if strings.Contains(t.String(), "SliceElem") { - return codeSliceElem - } - if t.String() == "Map" || t.String() == "MapPtr" { - return codeMapHead - } - if strings.Contains(t.String(), "MapKey") { - return codeMapKey - } - if strings.Contains(t.String(), "MapValue") { - return codeMapValue - } - if strings.Contains(t.String(), "MapEnd") { - return codeMapEnd + switch t { + case OpArray, OpArrayPtr: + return CodeArrayHead + case OpArrayElem: + return CodeArrayElem + case OpSlice, OpSlicePtr: + return CodeSliceHead + case OpSliceElem: + return CodeSliceElem + case OpMap, OpMapPtr: + return CodeMapHead + case OpMapKey: + return CodeMapKey + case OpMapValue: + return CodeMapValue + case OpMapEnd: + return CodeMapEnd } - return codeOp + return CodeOp } -func (t opType) headToPtrHead() opType { +func (t OpType) HeadToPtrHead() OpType { if strings.Index(t.String(), "PtrHead") > 0 { return t } - idx := strings.Index(t.String(), "Field") + idx := strings.Index(t.String(), "Head") if idx == -1 { return t } - suffix := "Ptr"+t.String()[idx+len("Field"):] + suffix := "Ptr"+t.String()[idx+len("Head"):] const toPtrOffset = 3 - if strings.Contains(opType(int(t) + toPtrOffset).String(), suffix) { - return opType(int(t) + toPtrOffset) + if strings.Contains(OpType(int(t) + toPtrOffset).String(), suffix) { + return OpType(int(t) + toPtrOffset) } return t } -func (t opType) headToOmitEmptyHead() opType { +func (t OpType) HeadToOmitEmptyHead() OpType { const toOmitEmptyOffset = 1 - if strings.Contains(opType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") { - return opType(int(t) + toOmitEmptyOffset) + if strings.Contains(OpType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") { + return OpType(int(t) + toOmitEmptyOffset) } return t } -func (t opType) headToStringTagHead() opType { +func (t OpType) HeadToStringTagHead() OpType { const toStringTagOffset = 2 - if strings.Contains(opType(int(t) + toStringTagOffset).String(), "StringTag") { - return opType(int(t) + toStringTagOffset) + if strings.Contains(OpType(int(t) + toStringTagOffset).String(), "StringTag") { + return OpType(int(t) + toStringTagOffset) } return t } -func (t opType) ptrHeadToHead() opType { +func (t OpType) PtrHeadToHead() OpType { idx := strings.Index(t.String(), "Ptr") if idx == -1 { return t @@ -180,36 +174,37 @@ func (t opType) ptrHeadToHead() opType { suffix := t.String()[idx+len("Ptr"):] const toPtrOffset = 3 - if strings.Contains(opType(int(t) - toPtrOffset).String(), suffix) { - return opType(int(t) - toPtrOffset) + if strings.Contains(OpType(int(t) - toPtrOffset).String(), suffix) { + return OpType(int(t) - toPtrOffset) } return t } -func (t opType) fieldToEnd() opType { - switch t { -{{- range $type := .OpTypes }} -{{- if $type.IsFieldToEnd }} - case op{{ $type.Op }}: - return op{{ call $type.FieldToEnd }} -{{- end }} -{{- end }} +func (t OpType) FieldToEnd() OpType { + idx := strings.Index(t.String(), "Field") + if idx == -1 { + return t + } + suffix := t.String()[idx+len("Field"):] + const toEndOffset = 3 + if strings.Contains(OpType(int(t) + toEndOffset).String(), "End"+suffix) { + return OpType(int(t) + toEndOffset) } return t } -func (t opType) fieldToOmitEmptyField() opType { +func (t OpType) FieldToOmitEmptyField() OpType { const toOmitEmptyOffset = 1 - if strings.Contains(opType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") { - return opType(int(t) + toOmitEmptyOffset) + if strings.Contains(OpType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") { + return OpType(int(t) + toOmitEmptyOffset) } return t } -func (t opType) fieldToStringTagField() opType { +func (t OpType) FieldToStringTagField() OpType { const toStringTagOffset = 2 - if strings.Contains(opType(int(t) + toStringTagOffset).String(), "StringTag") { - return opType(int(t) + toStringTagOffset) + if strings.Contains(OpType(int(t) + toStringTagOffset).String(), "StringTag") { + return OpType(int(t) + toStringTagOffset) } return t } @@ -269,7 +264,7 @@ func (t opType) fieldToStringTagField() opType { typ := typ op := fmt.Sprintf( - "StructField%sHead%s%s", + "Struct%sHead%s%s", ptrOrNot, opt, typ, @@ -279,28 +274,28 @@ func (t opType) fieldToStringTagField() opType { Code: "StructField", HeadToPtrHead: func() string { return fmt.Sprintf( - "StructFieldPtrHead%s%s", + "StructPtrHead%s%s", opt, typ, ) }, HeadToOmitEmptyHead: func() string { return fmt.Sprintf( - "StructField%sHeadOmitEmpty%s", + "Struct%sHeadOmitEmpty%s", ptrOrNot, typ, ) }, HeadToStringTagHead: func() string { return fmt.Sprintf( - "StructField%sHeadStringTag%s", + "Struct%sHeadStringTag%s", ptrOrNot, typ, ) }, PtrHeadToHead: func() string { return fmt.Sprintf( - "StructFieldHead%s%s", + "StructHead%s%s", opt, typ, ) @@ -354,8 +349,6 @@ func (t opType) fieldToStringTagField() opType { }, }) } - } - for _, typ := range append(primitiveTypesUpper, "") { for _, opt := range []string{"", "OmitEmpty", "StringTag"} { opt := opt typ := typ @@ -390,7 +383,7 @@ func (t opType) fieldToStringTagField() opType { }); err != nil { return err } - path := filepath.Join(repoRoot(), "encode_optype.go") + path := filepath.Join(repoRoot(), "internal", "encoder", "optype.go") buf, err := format.Source(b.Bytes()) if err != nil { return err @@ -400,10 +393,11 @@ func (t opType) fieldToStringTagField() opType { func repoRoot() string { _, file, _, _ := runtime.Caller(0) - relativePathFromRepoRoot := filepath.Join("cmd", "generator") + relativePathFromRepoRoot := filepath.Join("internal", "cmd", "generator") return strings.TrimSuffix(filepath.Dir(file), relativePathFromRepoRoot) } +//go:generate go run main.go func main() { if err := _main(); err != nil { panic(err) diff --git a/internal/encoder/compiler/compiler.go b/internal/encoder/compiler/compiler.go new file mode 100644 index 0000000..a20d4fe --- /dev/null +++ b/internal/encoder/compiler/compiler.go @@ -0,0 +1 @@ +package compiler diff --git a/internal/encoder/compiler/norace.go b/internal/encoder/compiler/norace.go new file mode 100644 index 0000000..8299204 --- /dev/null +++ b/internal/encoder/compiler/norace.go @@ -0,0 +1,11 @@ +// +build !race + +package compiler + +import ( + "github.com/goccy/go-json/internal/encoder" +) + +func CompileToGetCodeSet(typeptr uintptr) (*encoder.OpcodeSet, error) { + return nil, nil +} diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go new file mode 100644 index 0000000..26725fc --- /dev/null +++ b/internal/encoder/encoder.go @@ -0,0 +1,407 @@ +package encoder + +import ( + "bytes" + "encoding" + "encoding/base64" + "encoding/json" + "fmt" + "math" + "reflect" + "strconv" + "sync" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type Option int + +const ( + HTMLEscapeOption Option = 1 << iota + IndentOption + UnorderedMapOption +) + +type Opcode struct { + Op OpType // operation type + Type *runtime.Type // go type + DisplayIdx int // opcode index + Key []byte // struct field key + EscapedKey []byte // struct field key ( HTML escaped ) + PtrNum int // pointer number: e.g. double pointer is 2. + DisplayKey string // key text to display + IsTaggedKey bool // whether tagged key + AnonymousKey bool // whether anonymous key + AnonymousHead bool // whether anonymous head or not + Indirect bool // whether indirect or not + Nilcheck bool // whether needs to nilcheck or not + AddrForMarshaler bool // whether needs to addr for marshaler or not + RshiftNum uint8 // use to take bit for judging whether negative integer or not + Mask uint64 // mask for number + Indent int // indent number + + Idx uintptr // offset to access ptr + HeadIdx uintptr // offset to access slice/struct head + ElemIdx uintptr // offset to access array/slice/map elem + Length uintptr // offset to access slice/map length or array length + MapIter uintptr // offset to access map iterator + MapPos uintptr // offset to access position list for sorted map + Offset uintptr // offset size from struct header + Size uintptr // array/slice elem size + + MapKey *Opcode // map key + MapValue *Opcode // map value + Elem *Opcode // array/slice elem + End *Opcode // array/slice/struct/map end + PrevField *Opcode // prev struct field + NextField *Opcode // next struct field + Next *Opcode // next opcode + Jmp *CompiledCode // for recursive call +} + +type OpcodeSet struct { + Code *Opcode + CodeLength int +} + +type CompiledCode struct { + Code *Opcode + Linked bool // whether recursive code already have linked + CurLen uintptr + NextLen uintptr +} + +const StartDetectingCyclesAfter = 1000 + +func Load(base uintptr, idx uintptr) uintptr { + addr := base + idx + return **(**uintptr)(unsafe.Pointer(&addr)) +} + +func Store(base uintptr, idx uintptr, p uintptr) { + addr := base + idx + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func LoadAndStoreNPtr(base uintptr, idx uintptr, ptrNum int) { + addr := base + idx + p := **(**uintptr)(unsafe.Pointer(&addr)) + for i := 0; i < ptrNum; i++ { + if p == 0 { + **(**uintptr)(unsafe.Pointer(&addr)) = 0 + return + } + p = PtrToPtr(p) + } + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func PtrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } +func PtrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } +func PtrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } +func PtrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } +func PtrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } +func PtrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } +func PtrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } +func PtrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } +func PtrToPtr(p uintptr) uintptr { + return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) +} +func PtrToNPtr(p uintptr, ptrNum int) uintptr { + for i := 0; i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = PtrToPtr(p) + } + return p +} + +func PtrToUnsafePtr(p uintptr) unsafe.Pointer { + return *(*unsafe.Pointer)(unsafe.Pointer(&p)) +} +func PtrToInterface(code *Opcode, p uintptr) interface{} { + return *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) +} + +func ErrUnsupportedValue(code *Opcode, ptr uintptr) *errors.UnsupportedValueError { + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&ptr)), + })) + return &errors.UnsupportedValueError{ + Value: reflect.ValueOf(v), + Str: fmt.Sprintf("encountered a cycle via %s", code.Type), + } +} + +func ErrUnsupportedFloat(v float64) *errors.UnsupportedValueError { + return &errors.UnsupportedValueError{ + Value: reflect.ValueOf(v), + Str: strconv.FormatFloat(v, 'g', -1, 64), + } +} + +func ErrMarshalerWithCode(code *Opcode, err error) *errors.MarshalerError { + return &errors.MarshalerError{ + Type: runtime.RType2Type(code.Type), + Err: err, + } +} + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +type MapItem struct { + Key []byte + Value []byte +} + +type Mapslice struct { + Items []MapItem +} + +func (m *Mapslice) Len() int { + return len(m.Items) +} + +func (m *Mapslice) Less(i, j int) bool { + return bytes.Compare(m.Items[i].Key, m.Items[j].Key) < 0 +} + +func (m *Mapslice) Swap(i, j int) { + m.Items[i], m.Items[j] = m.Items[j], m.Items[i] +} + +type MapContext struct { + Pos []int + Slice *Mapslice + Buf []byte +} + +var mapContextPool = sync.Pool{ + New: func() interface{} { + return &MapContext{} + }, +} + +func NewMapContext(mapLen int) *MapContext { + ctx := mapContextPool.Get().(*MapContext) + if ctx.Slice == nil { + ctx.Slice = &Mapslice{ + Items: make([]MapItem, 0, mapLen), + } + } + if cap(ctx.Pos) < (mapLen*2 + 1) { + ctx.Pos = make([]int, 0, mapLen*2+1) + ctx.Slice.Items = make([]MapItem, 0, mapLen) + } else { + ctx.Pos = ctx.Pos[:0] + ctx.Slice.Items = ctx.Slice.Items[:0] + } + ctx.Buf = ctx.Buf[:0] + return ctx +} + +func ReleaseMapContext(c *MapContext) { + mapContextPool.Put(c) +} + +//go:linkname MapIterInit reflect.mapiterinit +//go:noescape +func MapIterInit(mapType *runtime.Type, m unsafe.Pointer) unsafe.Pointer + +//go:linkname MapIterKey reflect.mapiterkey +//go:noescape +func MapIterKey(it unsafe.Pointer) unsafe.Pointer + +//go:linkname MapIterNext reflect.mapiternext +//go:noescape +func MapIterNext(it unsafe.Pointer) + +//go:linkname MapLen reflect.maplen +//go:noescape +func MapLen(m unsafe.Pointer) int + +type RuntimeContext struct { + Buf []byte + Ptrs []uintptr + KeepRefs []unsafe.Pointer + SeenPtr []uintptr + BaseIndent int + Prefix []byte + IndentStr []byte +} + +func (c *RuntimeContext) Init(p uintptr, codelen int) { + if len(c.Ptrs) < codelen { + c.Ptrs = make([]uintptr, codelen) + } + c.Ptrs[0] = p + c.KeepRefs = c.KeepRefs[:0] + c.SeenPtr = c.SeenPtr[:0] + c.BaseIndent = 0 +} + +func (c *RuntimeContext) Ptr() uintptr { + header := (*runtime.SliceHeader)(unsafe.Pointer(&c.Ptrs)) + return uintptr(header.Data) +} + +func AppendByteSlice(b []byte, src []byte) []byte { + if src == nil { + return append(b, `null`...) + } + encodedLen := base64.StdEncoding.EncodedLen(len(src)) + b = append(b, '"') + pos := len(b) + remainLen := cap(b[pos:]) + var buf []byte + if remainLen > encodedLen { + buf = b[pos : pos+encodedLen] + } else { + buf = make([]byte, encodedLen) + } + base64.StdEncoding.Encode(buf, src) + return append(append(b, buf...), '"') +} + +func AppendFloat32(b []byte, v float32) []byte { + f64 := float64(v) + abs := math.Abs(f64) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + f32 := float32(abs) + if f32 < 1e-6 || f32 >= 1e21 { + fmt = 'e' + } + } + return strconv.AppendFloat(b, f64, fmt, -1, 32) +} + +func AppendFloat64(b []byte, v float64) []byte { + abs := math.Abs(v) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if abs < 1e-6 || abs >= 1e21 { + fmt = 'e' + } + } + return strconv.AppendFloat(b, v, fmt, -1, 64) +} + +func AppendBool(b []byte, v bool) []byte { + if v { + return append(b, "true"...) + } + return append(b, "false"...) +} + +var ( + floatTable = [256]bool{ + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + '.': true, + 'e': true, + 'E': true, + '+': true, + '-': true, + } +) + +func AppendNumber(b []byte, n json.Number) ([]byte, error) { + if len(n) == 0 { + return append(b, '0'), nil + } + for i := 0; i < len(n); i++ { + if !floatTable[n[i]] { + return nil, fmt.Errorf("json: invalid number literal %q", n) + } + } + b = append(b, n...) + return b, nil +} + +func AppendMarshalJSON(code *Opcode, b []byte, v interface{}, escape bool) ([]byte, error) { + rv := reflect.ValueOf(v) // convert by dynamic interface type + if code.AddrForMarshaler { + if rv.CanAddr() { + rv = rv.Addr() + } else { + newV := reflect.New(rv.Type()) + newV.Elem().Set(rv) + rv = newV + } + } + v = rv.Interface() + marshaler, ok := v.(json.Marshaler) + if !ok { + return AppendNull(b), nil + } + bb, err := marshaler.MarshalJSON() + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + return bb, nil + //buf := bytes.NewBuffer(b) + //TODO: we should validate buffer with `compact` + // if err := compact(buf, bb, escape); err != nil { + // return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + // } + //return buf.Bytes(), nil +} + +func AppendMarshalText(code *Opcode, b []byte, v interface{}, escape bool) ([]byte, error) { + rv := reflect.ValueOf(v) // convert by dynamic interface type + if code.AddrForMarshaler { + if rv.CanAddr() { + rv = rv.Addr() + } else { + newV := reflect.New(rv.Type()) + newV.Elem().Set(rv) + rv = newV + } + } + v = rv.Interface() + marshaler, ok := v.(encoding.TextMarshaler) + if !ok { + return AppendNull(b), nil + } + bytes, err := marshaler.MarshalText() + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + if escape { + return AppendEscapedString(b, *(*string)(unsafe.Pointer(&bytes))), nil + } + return AppendString(b, *(*string)(unsafe.Pointer(&bytes))), nil +} + +func AppendNull(b []byte) []byte { + return append(b, "null"...) +} + +func AppendComma(b []byte) []byte { + return append(b, ',') +} + +func AppendStructEnd(b []byte) []byte { + return append(b, '}', ',') +} diff --git a/internal/encoder/int.go b/internal/encoder/int.go new file mode 100644 index 0000000..70ea5f7 --- /dev/null +++ b/internal/encoder/int.go @@ -0,0 +1,124 @@ +package encoder + +import ( + "unsafe" +) + +var endianness int + +func init() { + var b [2]byte + *(*uint16)(unsafe.Pointer(&b)) = uint16(0xABCD) + + switch b[0] { + case 0xCD: + endianness = 0 // LE + case 0xAB: + endianness = 1 // BE + default: + panic("could not determine endianness") + } +} + +// "00010203...96979899" cast to []uint16 +var intLELookup = [100]uint16{ + 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, + 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, + 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, + 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933, + 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934, + 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, + 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, + 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, + 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938, + 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939, +} + +var intBELookup = [100]uint16{ + 0x3030, 0x3031, 0x3032, 0x3033, 0x3034, 0x3035, 0x3036, 0x3037, 0x3038, 0x3039, + 0x3130, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138, 0x3139, + 0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3236, 0x3237, 0x3238, 0x3239, + 0x3330, 0x3331, 0x3332, 0x3333, 0x3334, 0x3335, 0x3336, 0x3337, 0x3338, 0x3339, + 0x3430, 0x3431, 0x3432, 0x3433, 0x3434, 0x3435, 0x3436, 0x3437, 0x3438, 0x3439, + 0x3530, 0x3531, 0x3532, 0x3533, 0x3534, 0x3535, 0x3536, 0x3537, 0x3538, 0x3539, + 0x3630, 0x3631, 0x3632, 0x3633, 0x3634, 0x3635, 0x3636, 0x3637, 0x3638, 0x3639, + 0x3730, 0x3731, 0x3732, 0x3733, 0x3734, 0x3735, 0x3736, 0x3737, 0x3738, 0x3739, + 0x3830, 0x3831, 0x3832, 0x3833, 0x3834, 0x3835, 0x3836, 0x3837, 0x3838, 0x3839, + 0x3930, 0x3931, 0x3932, 0x3933, 0x3934, 0x3935, 0x3936, 0x3937, 0x3938, 0x3939, +} + +var intLookup = [2]*[100]uint16{&intLELookup, &intBELookup} + +func AppendInt(out []byte, u64 uint64, code *Opcode) []byte { + n := u64 & code.Mask + negative := (u64>>code.RshiftNum)&1 == 1 + if !negative { + if n < 10 { + return append(out, byte(n+'0')) + } else if n < 100 { + u := intLELookup[n] + return append(out, byte(u), byte(u>>8)) + } + } else { + n = -n & code.Mask + } + + lookup := intLookup[endianness] + + var b [22]byte + u := (*[11]uint16)(unsafe.Pointer(&b)) + i := 11 + + for n >= 100 { + j := n % 100 + n /= 100 + i-- + u[i] = lookup[j] + } + + i-- + u[i] = lookup[n] + + i *= 2 // convert to byte index + if n < 10 { + i++ // remove leading zero + } + if negative { + i-- + b[i] = '-' + } + + return append(out, b[i:]...) +} + +func AppendUint(out []byte, u64 uint64, code *Opcode) []byte { + n := u64 & code.Mask + if n < 10 { + return append(out, byte(n+'0')) + } else if n < 100 { + u := intLELookup[n] + return append(out, byte(u), byte(u>>8)) + } + + lookup := intLookup[endianness] + + var b [22]byte + u := (*[11]uint16)(unsafe.Pointer(&b)) + i := 11 + + for n >= 100 { + j := n % 100 + n /= 100 + i-- + u[i] = lookup[j] + } + + i-- + u[i] = lookup[n] + + i *= 2 // convert to byte index + if n < 10 { + i++ // remove leading zero + } + return append(out, b[i:]...) +} diff --git a/internal/encoder/map112.go b/internal/encoder/map112.go new file mode 100644 index 0000000..31858d0 --- /dev/null +++ b/internal/encoder/map112.go @@ -0,0 +1,8 @@ +// +build !go1.13 + +package encoder + +import "unsafe" + +//go:linkname MapIterValue reflect.mapitervalue +func MapIterValue(it unsafe.Pointer) unsafe.Pointer diff --git a/internal/encoder/map113.go b/internal/encoder/map113.go new file mode 100644 index 0000000..f49c27b --- /dev/null +++ b/internal/encoder/map113.go @@ -0,0 +1,8 @@ +// +build go1.13 + +package encoder + +import "unsafe" + +//go:linkname MapIterValue reflect.mapiterelem +func MapIterValue(it unsafe.Pointer) unsafe.Pointer diff --git a/internal/encoder/optype.go b/internal/encoder/optype.go new file mode 100644 index 0000000..b0641c2 --- /dev/null +++ b/internal/encoder/optype.go @@ -0,0 +1,1025 @@ +// Code generated by internal/cmd/generator. DO NOT EDIT! +package encoder + +import ( + "strings" +) + +type CodeType int + +const ( + CodeOp CodeType = 0 + CodeArrayHead CodeType = 1 + CodeArrayElem CodeType = 2 + CodeSliceHead CodeType = 3 + CodeSliceElem CodeType = 4 + CodeMapHead CodeType = 5 + CodeMapKey CodeType = 6 + CodeMapValue CodeType = 7 + CodeMapEnd CodeType = 8 + CodeStructFieldRecursive CodeType = 9 + CodeStructField CodeType = 10 + CodeStructEnd CodeType = 11 +) + +var opTypeStrings = [440]string{ + "End", + "Interface", + "Ptr", + "SliceElem", + "SliceEnd", + "ArrayElem", + "ArrayEnd", + "MapKey", + "MapValue", + "MapEnd", + "StructFieldRecursiveEnd", + "StructAnonymousEnd", + "Int", + "Uint", + "Float32", + "Float64", + "Bool", + "String", + "Bytes", + "Number", + "Array", + "Map", + "Slice", + "Struct", + "MarshalJSON", + "MarshalText", + "Recursive", + "IntString", + "UintString", + "IntPtr", + "UintPtr", + "Float32Ptr", + "Float64Ptr", + "BoolPtr", + "StringPtr", + "BytesPtr", + "NumberPtr", + "ArrayPtr", + "MapPtr", + "SlicePtr", + "MarshalJSONPtr", + "MarshalTextPtr", + "InterfacePtr", + "RecursivePtr", + "StructHeadInt", + "StructHeadOmitEmptyInt", + "StructHeadStringTagInt", + "StructPtrHeadInt", + "StructPtrHeadOmitEmptyInt", + "StructPtrHeadStringTagInt", + "StructHeadUint", + "StructHeadOmitEmptyUint", + "StructHeadStringTagUint", + "StructPtrHeadUint", + "StructPtrHeadOmitEmptyUint", + "StructPtrHeadStringTagUint", + "StructHeadFloat32", + "StructHeadOmitEmptyFloat32", + "StructHeadStringTagFloat32", + "StructPtrHeadFloat32", + "StructPtrHeadOmitEmptyFloat32", + "StructPtrHeadStringTagFloat32", + "StructHeadFloat64", + "StructHeadOmitEmptyFloat64", + "StructHeadStringTagFloat64", + "StructPtrHeadFloat64", + "StructPtrHeadOmitEmptyFloat64", + "StructPtrHeadStringTagFloat64", + "StructHeadBool", + "StructHeadOmitEmptyBool", + "StructHeadStringTagBool", + "StructPtrHeadBool", + "StructPtrHeadOmitEmptyBool", + "StructPtrHeadStringTagBool", + "StructHeadString", + "StructHeadOmitEmptyString", + "StructHeadStringTagString", + "StructPtrHeadString", + "StructPtrHeadOmitEmptyString", + "StructPtrHeadStringTagString", + "StructHeadBytes", + "StructHeadOmitEmptyBytes", + "StructHeadStringTagBytes", + "StructPtrHeadBytes", + "StructPtrHeadOmitEmptyBytes", + "StructPtrHeadStringTagBytes", + "StructHeadNumber", + "StructHeadOmitEmptyNumber", + "StructHeadStringTagNumber", + "StructPtrHeadNumber", + "StructPtrHeadOmitEmptyNumber", + "StructPtrHeadStringTagNumber", + "StructHeadArray", + "StructHeadOmitEmptyArray", + "StructHeadStringTagArray", + "StructPtrHeadArray", + "StructPtrHeadOmitEmptyArray", + "StructPtrHeadStringTagArray", + "StructHeadMap", + "StructHeadOmitEmptyMap", + "StructHeadStringTagMap", + "StructPtrHeadMap", + "StructPtrHeadOmitEmptyMap", + "StructPtrHeadStringTagMap", + "StructHeadSlice", + "StructHeadOmitEmptySlice", + "StructHeadStringTagSlice", + "StructPtrHeadSlice", + "StructPtrHeadOmitEmptySlice", + "StructPtrHeadStringTagSlice", + "StructHeadStruct", + "StructHeadOmitEmptyStruct", + "StructHeadStringTagStruct", + "StructPtrHeadStruct", + "StructPtrHeadOmitEmptyStruct", + "StructPtrHeadStringTagStruct", + "StructHeadMarshalJSON", + "StructHeadOmitEmptyMarshalJSON", + "StructHeadStringTagMarshalJSON", + "StructPtrHeadMarshalJSON", + "StructPtrHeadOmitEmptyMarshalJSON", + "StructPtrHeadStringTagMarshalJSON", + "StructHeadMarshalText", + "StructHeadOmitEmptyMarshalText", + "StructHeadStringTagMarshalText", + "StructPtrHeadMarshalText", + "StructPtrHeadOmitEmptyMarshalText", + "StructPtrHeadStringTagMarshalText", + "StructHeadRecursive", + "StructHeadOmitEmptyRecursive", + "StructHeadStringTagRecursive", + "StructPtrHeadRecursive", + "StructPtrHeadOmitEmptyRecursive", + "StructPtrHeadStringTagRecursive", + "StructHeadIntString", + "StructHeadOmitEmptyIntString", + "StructHeadStringTagIntString", + "StructPtrHeadIntString", + "StructPtrHeadOmitEmptyIntString", + "StructPtrHeadStringTagIntString", + "StructHeadUintString", + "StructHeadOmitEmptyUintString", + "StructHeadStringTagUintString", + "StructPtrHeadUintString", + "StructPtrHeadOmitEmptyUintString", + "StructPtrHeadStringTagUintString", + "StructHeadIntPtr", + "StructHeadOmitEmptyIntPtr", + "StructHeadStringTagIntPtr", + "StructPtrHeadIntPtr", + "StructPtrHeadOmitEmptyIntPtr", + "StructPtrHeadStringTagIntPtr", + "StructHeadUintPtr", + "StructHeadOmitEmptyUintPtr", + "StructHeadStringTagUintPtr", + "StructPtrHeadUintPtr", + "StructPtrHeadOmitEmptyUintPtr", + "StructPtrHeadStringTagUintPtr", + "StructHeadFloat32Ptr", + "StructHeadOmitEmptyFloat32Ptr", + "StructHeadStringTagFloat32Ptr", + "StructPtrHeadFloat32Ptr", + "StructPtrHeadOmitEmptyFloat32Ptr", + "StructPtrHeadStringTagFloat32Ptr", + "StructHeadFloat64Ptr", + "StructHeadOmitEmptyFloat64Ptr", + "StructHeadStringTagFloat64Ptr", + "StructPtrHeadFloat64Ptr", + "StructPtrHeadOmitEmptyFloat64Ptr", + "StructPtrHeadStringTagFloat64Ptr", + "StructHeadBoolPtr", + "StructHeadOmitEmptyBoolPtr", + "StructHeadStringTagBoolPtr", + "StructPtrHeadBoolPtr", + "StructPtrHeadOmitEmptyBoolPtr", + "StructPtrHeadStringTagBoolPtr", + "StructHeadStringPtr", + "StructHeadOmitEmptyStringPtr", + "StructHeadStringTagStringPtr", + "StructPtrHeadStringPtr", + "StructPtrHeadOmitEmptyStringPtr", + "StructPtrHeadStringTagStringPtr", + "StructHeadBytesPtr", + "StructHeadOmitEmptyBytesPtr", + "StructHeadStringTagBytesPtr", + "StructPtrHeadBytesPtr", + "StructPtrHeadOmitEmptyBytesPtr", + "StructPtrHeadStringTagBytesPtr", + "StructHeadNumberPtr", + "StructHeadOmitEmptyNumberPtr", + "StructHeadStringTagNumberPtr", + "StructPtrHeadNumberPtr", + "StructPtrHeadOmitEmptyNumberPtr", + "StructPtrHeadStringTagNumberPtr", + "StructHeadArrayPtr", + "StructHeadOmitEmptyArrayPtr", + "StructHeadStringTagArrayPtr", + "StructPtrHeadArrayPtr", + "StructPtrHeadOmitEmptyArrayPtr", + "StructPtrHeadStringTagArrayPtr", + "StructHeadMapPtr", + "StructHeadOmitEmptyMapPtr", + "StructHeadStringTagMapPtr", + "StructPtrHeadMapPtr", + "StructPtrHeadOmitEmptyMapPtr", + "StructPtrHeadStringTagMapPtr", + "StructHeadSlicePtr", + "StructHeadOmitEmptySlicePtr", + "StructHeadStringTagSlicePtr", + "StructPtrHeadSlicePtr", + "StructPtrHeadOmitEmptySlicePtr", + "StructPtrHeadStringTagSlicePtr", + "StructHeadMarshalJSONPtr", + "StructHeadOmitEmptyMarshalJSONPtr", + "StructHeadStringTagMarshalJSONPtr", + "StructPtrHeadMarshalJSONPtr", + "StructPtrHeadOmitEmptyMarshalJSONPtr", + "StructPtrHeadStringTagMarshalJSONPtr", + "StructHeadMarshalTextPtr", + "StructHeadOmitEmptyMarshalTextPtr", + "StructHeadStringTagMarshalTextPtr", + "StructPtrHeadMarshalTextPtr", + "StructPtrHeadOmitEmptyMarshalTextPtr", + "StructPtrHeadStringTagMarshalTextPtr", + "StructHeadInterfacePtr", + "StructHeadOmitEmptyInterfacePtr", + "StructHeadStringTagInterfacePtr", + "StructPtrHeadInterfacePtr", + "StructPtrHeadOmitEmptyInterfacePtr", + "StructPtrHeadStringTagInterfacePtr", + "StructHeadRecursivePtr", + "StructHeadOmitEmptyRecursivePtr", + "StructHeadStringTagRecursivePtr", + "StructPtrHeadRecursivePtr", + "StructPtrHeadOmitEmptyRecursivePtr", + "StructPtrHeadStringTagRecursivePtr", + "StructHead", + "StructHeadOmitEmpty", + "StructHeadStringTag", + "StructPtrHead", + "StructPtrHeadOmitEmpty", + "StructPtrHeadStringTag", + "StructFieldInt", + "StructFieldOmitEmptyInt", + "StructFieldStringTagInt", + "StructEndInt", + "StructEndOmitEmptyInt", + "StructEndStringTagInt", + "StructFieldUint", + "StructFieldOmitEmptyUint", + "StructFieldStringTagUint", + "StructEndUint", + "StructEndOmitEmptyUint", + "StructEndStringTagUint", + "StructFieldFloat32", + "StructFieldOmitEmptyFloat32", + "StructFieldStringTagFloat32", + "StructEndFloat32", + "StructEndOmitEmptyFloat32", + "StructEndStringTagFloat32", + "StructFieldFloat64", + "StructFieldOmitEmptyFloat64", + "StructFieldStringTagFloat64", + "StructEndFloat64", + "StructEndOmitEmptyFloat64", + "StructEndStringTagFloat64", + "StructFieldBool", + "StructFieldOmitEmptyBool", + "StructFieldStringTagBool", + "StructEndBool", + "StructEndOmitEmptyBool", + "StructEndStringTagBool", + "StructFieldString", + "StructFieldOmitEmptyString", + "StructFieldStringTagString", + "StructEndString", + "StructEndOmitEmptyString", + "StructEndStringTagString", + "StructFieldBytes", + "StructFieldOmitEmptyBytes", + "StructFieldStringTagBytes", + "StructEndBytes", + "StructEndOmitEmptyBytes", + "StructEndStringTagBytes", + "StructFieldNumber", + "StructFieldOmitEmptyNumber", + "StructFieldStringTagNumber", + "StructEndNumber", + "StructEndOmitEmptyNumber", + "StructEndStringTagNumber", + "StructFieldArray", + "StructFieldOmitEmptyArray", + "StructFieldStringTagArray", + "StructEndArray", + "StructEndOmitEmptyArray", + "StructEndStringTagArray", + "StructFieldMap", + "StructFieldOmitEmptyMap", + "StructFieldStringTagMap", + "StructEndMap", + "StructEndOmitEmptyMap", + "StructEndStringTagMap", + "StructFieldSlice", + "StructFieldOmitEmptySlice", + "StructFieldStringTagSlice", + "StructEndSlice", + "StructEndOmitEmptySlice", + "StructEndStringTagSlice", + "StructFieldStruct", + "StructFieldOmitEmptyStruct", + "StructFieldStringTagStruct", + "StructEndStruct", + "StructEndOmitEmptyStruct", + "StructEndStringTagStruct", + "StructFieldMarshalJSON", + "StructFieldOmitEmptyMarshalJSON", + "StructFieldStringTagMarshalJSON", + "StructEndMarshalJSON", + "StructEndOmitEmptyMarshalJSON", + "StructEndStringTagMarshalJSON", + "StructFieldMarshalText", + "StructFieldOmitEmptyMarshalText", + "StructFieldStringTagMarshalText", + "StructEndMarshalText", + "StructEndOmitEmptyMarshalText", + "StructEndStringTagMarshalText", + "StructFieldRecursive", + "StructFieldOmitEmptyRecursive", + "StructFieldStringTagRecursive", + "StructEndRecursive", + "StructEndOmitEmptyRecursive", + "StructEndStringTagRecursive", + "StructFieldIntString", + "StructFieldOmitEmptyIntString", + "StructFieldStringTagIntString", + "StructEndIntString", + "StructEndOmitEmptyIntString", + "StructEndStringTagIntString", + "StructFieldUintString", + "StructFieldOmitEmptyUintString", + "StructFieldStringTagUintString", + "StructEndUintString", + "StructEndOmitEmptyUintString", + "StructEndStringTagUintString", + "StructFieldIntPtr", + "StructFieldOmitEmptyIntPtr", + "StructFieldStringTagIntPtr", + "StructEndIntPtr", + "StructEndOmitEmptyIntPtr", + "StructEndStringTagIntPtr", + "StructFieldUintPtr", + "StructFieldOmitEmptyUintPtr", + "StructFieldStringTagUintPtr", + "StructEndUintPtr", + "StructEndOmitEmptyUintPtr", + "StructEndStringTagUintPtr", + "StructFieldFloat32Ptr", + "StructFieldOmitEmptyFloat32Ptr", + "StructFieldStringTagFloat32Ptr", + "StructEndFloat32Ptr", + "StructEndOmitEmptyFloat32Ptr", + "StructEndStringTagFloat32Ptr", + "StructFieldFloat64Ptr", + "StructFieldOmitEmptyFloat64Ptr", + "StructFieldStringTagFloat64Ptr", + "StructEndFloat64Ptr", + "StructEndOmitEmptyFloat64Ptr", + "StructEndStringTagFloat64Ptr", + "StructFieldBoolPtr", + "StructFieldOmitEmptyBoolPtr", + "StructFieldStringTagBoolPtr", + "StructEndBoolPtr", + "StructEndOmitEmptyBoolPtr", + "StructEndStringTagBoolPtr", + "StructFieldStringPtr", + "StructFieldOmitEmptyStringPtr", + "StructFieldStringTagStringPtr", + "StructEndStringPtr", + "StructEndOmitEmptyStringPtr", + "StructEndStringTagStringPtr", + "StructFieldBytesPtr", + "StructFieldOmitEmptyBytesPtr", + "StructFieldStringTagBytesPtr", + "StructEndBytesPtr", + "StructEndOmitEmptyBytesPtr", + "StructEndStringTagBytesPtr", + "StructFieldNumberPtr", + "StructFieldOmitEmptyNumberPtr", + "StructFieldStringTagNumberPtr", + "StructEndNumberPtr", + "StructEndOmitEmptyNumberPtr", + "StructEndStringTagNumberPtr", + "StructFieldArrayPtr", + "StructFieldOmitEmptyArrayPtr", + "StructFieldStringTagArrayPtr", + "StructEndArrayPtr", + "StructEndOmitEmptyArrayPtr", + "StructEndStringTagArrayPtr", + "StructFieldMapPtr", + "StructFieldOmitEmptyMapPtr", + "StructFieldStringTagMapPtr", + "StructEndMapPtr", + "StructEndOmitEmptyMapPtr", + "StructEndStringTagMapPtr", + "StructFieldSlicePtr", + "StructFieldOmitEmptySlicePtr", + "StructFieldStringTagSlicePtr", + "StructEndSlicePtr", + "StructEndOmitEmptySlicePtr", + "StructEndStringTagSlicePtr", + "StructFieldMarshalJSONPtr", + "StructFieldOmitEmptyMarshalJSONPtr", + "StructFieldStringTagMarshalJSONPtr", + "StructEndMarshalJSONPtr", + "StructEndOmitEmptyMarshalJSONPtr", + "StructEndStringTagMarshalJSONPtr", + "StructFieldMarshalTextPtr", + "StructFieldOmitEmptyMarshalTextPtr", + "StructFieldStringTagMarshalTextPtr", + "StructEndMarshalTextPtr", + "StructEndOmitEmptyMarshalTextPtr", + "StructEndStringTagMarshalTextPtr", + "StructFieldInterfacePtr", + "StructFieldOmitEmptyInterfacePtr", + "StructFieldStringTagInterfacePtr", + "StructEndInterfacePtr", + "StructEndOmitEmptyInterfacePtr", + "StructEndStringTagInterfacePtr", + "StructFieldRecursivePtr", + "StructFieldOmitEmptyRecursivePtr", + "StructFieldStringTagRecursivePtr", + "StructEndRecursivePtr", + "StructEndOmitEmptyRecursivePtr", + "StructEndStringTagRecursivePtr", + "StructField", + "StructFieldOmitEmpty", + "StructFieldStringTag", + "StructEnd", + "StructEndOmitEmpty", + "StructEndStringTag", +} + +type OpType int + +const ( + OpEnd OpType = 0 + OpInterface OpType = 1 + OpPtr OpType = 2 + OpSliceElem OpType = 3 + OpSliceEnd OpType = 4 + OpArrayElem OpType = 5 + OpArrayEnd OpType = 6 + OpMapKey OpType = 7 + OpMapValue OpType = 8 + OpMapEnd OpType = 9 + OpStructFieldRecursiveEnd OpType = 10 + OpStructAnonymousEnd OpType = 11 + OpInt OpType = 12 + OpUint OpType = 13 + OpFloat32 OpType = 14 + OpFloat64 OpType = 15 + OpBool OpType = 16 + OpString OpType = 17 + OpBytes OpType = 18 + OpNumber OpType = 19 + OpArray OpType = 20 + OpMap OpType = 21 + OpSlice OpType = 22 + OpStruct OpType = 23 + OpMarshalJSON OpType = 24 + OpMarshalText OpType = 25 + OpRecursive OpType = 26 + OpIntString OpType = 27 + OpUintString OpType = 28 + OpIntPtr OpType = 29 + OpUintPtr OpType = 30 + OpFloat32Ptr OpType = 31 + OpFloat64Ptr OpType = 32 + OpBoolPtr OpType = 33 + OpStringPtr OpType = 34 + OpBytesPtr OpType = 35 + OpNumberPtr OpType = 36 + OpArrayPtr OpType = 37 + OpMapPtr OpType = 38 + OpSlicePtr OpType = 39 + OpMarshalJSONPtr OpType = 40 + OpMarshalTextPtr OpType = 41 + OpInterfacePtr OpType = 42 + OpRecursivePtr OpType = 43 + OpStructHeadInt OpType = 44 + OpStructHeadOmitEmptyInt OpType = 45 + OpStructHeadStringTagInt OpType = 46 + OpStructPtrHeadInt OpType = 47 + OpStructPtrHeadOmitEmptyInt OpType = 48 + OpStructPtrHeadStringTagInt OpType = 49 + OpStructHeadUint OpType = 50 + OpStructHeadOmitEmptyUint OpType = 51 + OpStructHeadStringTagUint OpType = 52 + OpStructPtrHeadUint OpType = 53 + OpStructPtrHeadOmitEmptyUint OpType = 54 + OpStructPtrHeadStringTagUint OpType = 55 + OpStructHeadFloat32 OpType = 56 + OpStructHeadOmitEmptyFloat32 OpType = 57 + OpStructHeadStringTagFloat32 OpType = 58 + OpStructPtrHeadFloat32 OpType = 59 + OpStructPtrHeadOmitEmptyFloat32 OpType = 60 + OpStructPtrHeadStringTagFloat32 OpType = 61 + OpStructHeadFloat64 OpType = 62 + OpStructHeadOmitEmptyFloat64 OpType = 63 + OpStructHeadStringTagFloat64 OpType = 64 + OpStructPtrHeadFloat64 OpType = 65 + OpStructPtrHeadOmitEmptyFloat64 OpType = 66 + OpStructPtrHeadStringTagFloat64 OpType = 67 + OpStructHeadBool OpType = 68 + OpStructHeadOmitEmptyBool OpType = 69 + OpStructHeadStringTagBool OpType = 70 + OpStructPtrHeadBool OpType = 71 + OpStructPtrHeadOmitEmptyBool OpType = 72 + OpStructPtrHeadStringTagBool OpType = 73 + OpStructHeadString OpType = 74 + OpStructHeadOmitEmptyString OpType = 75 + OpStructHeadStringTagString OpType = 76 + OpStructPtrHeadString OpType = 77 + OpStructPtrHeadOmitEmptyString OpType = 78 + OpStructPtrHeadStringTagString OpType = 79 + OpStructHeadBytes OpType = 80 + OpStructHeadOmitEmptyBytes OpType = 81 + OpStructHeadStringTagBytes OpType = 82 + OpStructPtrHeadBytes OpType = 83 + OpStructPtrHeadOmitEmptyBytes OpType = 84 + OpStructPtrHeadStringTagBytes OpType = 85 + OpStructHeadNumber OpType = 86 + OpStructHeadOmitEmptyNumber OpType = 87 + OpStructHeadStringTagNumber OpType = 88 + OpStructPtrHeadNumber OpType = 89 + OpStructPtrHeadOmitEmptyNumber OpType = 90 + OpStructPtrHeadStringTagNumber OpType = 91 + OpStructHeadArray OpType = 92 + OpStructHeadOmitEmptyArray OpType = 93 + OpStructHeadStringTagArray OpType = 94 + OpStructPtrHeadArray OpType = 95 + OpStructPtrHeadOmitEmptyArray OpType = 96 + OpStructPtrHeadStringTagArray OpType = 97 + OpStructHeadMap OpType = 98 + OpStructHeadOmitEmptyMap OpType = 99 + OpStructHeadStringTagMap OpType = 100 + OpStructPtrHeadMap OpType = 101 + OpStructPtrHeadOmitEmptyMap OpType = 102 + OpStructPtrHeadStringTagMap OpType = 103 + OpStructHeadSlice OpType = 104 + OpStructHeadOmitEmptySlice OpType = 105 + OpStructHeadStringTagSlice OpType = 106 + OpStructPtrHeadSlice OpType = 107 + OpStructPtrHeadOmitEmptySlice OpType = 108 + OpStructPtrHeadStringTagSlice OpType = 109 + OpStructHeadStruct OpType = 110 + OpStructHeadOmitEmptyStruct OpType = 111 + OpStructHeadStringTagStruct OpType = 112 + OpStructPtrHeadStruct OpType = 113 + OpStructPtrHeadOmitEmptyStruct OpType = 114 + OpStructPtrHeadStringTagStruct OpType = 115 + OpStructHeadMarshalJSON OpType = 116 + OpStructHeadOmitEmptyMarshalJSON OpType = 117 + OpStructHeadStringTagMarshalJSON OpType = 118 + OpStructPtrHeadMarshalJSON OpType = 119 + OpStructPtrHeadOmitEmptyMarshalJSON OpType = 120 + OpStructPtrHeadStringTagMarshalJSON OpType = 121 + OpStructHeadMarshalText OpType = 122 + OpStructHeadOmitEmptyMarshalText OpType = 123 + OpStructHeadStringTagMarshalText OpType = 124 + OpStructPtrHeadMarshalText OpType = 125 + OpStructPtrHeadOmitEmptyMarshalText OpType = 126 + OpStructPtrHeadStringTagMarshalText OpType = 127 + OpStructHeadRecursive OpType = 128 + OpStructHeadOmitEmptyRecursive OpType = 129 + OpStructHeadStringTagRecursive OpType = 130 + OpStructPtrHeadRecursive OpType = 131 + OpStructPtrHeadOmitEmptyRecursive OpType = 132 + OpStructPtrHeadStringTagRecursive OpType = 133 + OpStructHeadIntString OpType = 134 + OpStructHeadOmitEmptyIntString OpType = 135 + OpStructHeadStringTagIntString OpType = 136 + OpStructPtrHeadIntString OpType = 137 + OpStructPtrHeadOmitEmptyIntString OpType = 138 + OpStructPtrHeadStringTagIntString OpType = 139 + OpStructHeadUintString OpType = 140 + OpStructHeadOmitEmptyUintString OpType = 141 + OpStructHeadStringTagUintString OpType = 142 + OpStructPtrHeadUintString OpType = 143 + OpStructPtrHeadOmitEmptyUintString OpType = 144 + OpStructPtrHeadStringTagUintString OpType = 145 + OpStructHeadIntPtr OpType = 146 + OpStructHeadOmitEmptyIntPtr OpType = 147 + OpStructHeadStringTagIntPtr OpType = 148 + OpStructPtrHeadIntPtr OpType = 149 + OpStructPtrHeadOmitEmptyIntPtr OpType = 150 + OpStructPtrHeadStringTagIntPtr OpType = 151 + OpStructHeadUintPtr OpType = 152 + OpStructHeadOmitEmptyUintPtr OpType = 153 + OpStructHeadStringTagUintPtr OpType = 154 + OpStructPtrHeadUintPtr OpType = 155 + OpStructPtrHeadOmitEmptyUintPtr OpType = 156 + OpStructPtrHeadStringTagUintPtr OpType = 157 + OpStructHeadFloat32Ptr OpType = 158 + OpStructHeadOmitEmptyFloat32Ptr OpType = 159 + OpStructHeadStringTagFloat32Ptr OpType = 160 + OpStructPtrHeadFloat32Ptr OpType = 161 + OpStructPtrHeadOmitEmptyFloat32Ptr OpType = 162 + OpStructPtrHeadStringTagFloat32Ptr OpType = 163 + OpStructHeadFloat64Ptr OpType = 164 + OpStructHeadOmitEmptyFloat64Ptr OpType = 165 + OpStructHeadStringTagFloat64Ptr OpType = 166 + OpStructPtrHeadFloat64Ptr OpType = 167 + OpStructPtrHeadOmitEmptyFloat64Ptr OpType = 168 + OpStructPtrHeadStringTagFloat64Ptr OpType = 169 + OpStructHeadBoolPtr OpType = 170 + OpStructHeadOmitEmptyBoolPtr OpType = 171 + OpStructHeadStringTagBoolPtr OpType = 172 + OpStructPtrHeadBoolPtr OpType = 173 + OpStructPtrHeadOmitEmptyBoolPtr OpType = 174 + OpStructPtrHeadStringTagBoolPtr OpType = 175 + OpStructHeadStringPtr OpType = 176 + OpStructHeadOmitEmptyStringPtr OpType = 177 + OpStructHeadStringTagStringPtr OpType = 178 + OpStructPtrHeadStringPtr OpType = 179 + OpStructPtrHeadOmitEmptyStringPtr OpType = 180 + OpStructPtrHeadStringTagStringPtr OpType = 181 + OpStructHeadBytesPtr OpType = 182 + OpStructHeadOmitEmptyBytesPtr OpType = 183 + OpStructHeadStringTagBytesPtr OpType = 184 + OpStructPtrHeadBytesPtr OpType = 185 + OpStructPtrHeadOmitEmptyBytesPtr OpType = 186 + OpStructPtrHeadStringTagBytesPtr OpType = 187 + OpStructHeadNumberPtr OpType = 188 + OpStructHeadOmitEmptyNumberPtr OpType = 189 + OpStructHeadStringTagNumberPtr OpType = 190 + OpStructPtrHeadNumberPtr OpType = 191 + OpStructPtrHeadOmitEmptyNumberPtr OpType = 192 + OpStructPtrHeadStringTagNumberPtr OpType = 193 + OpStructHeadArrayPtr OpType = 194 + OpStructHeadOmitEmptyArrayPtr OpType = 195 + OpStructHeadStringTagArrayPtr OpType = 196 + OpStructPtrHeadArrayPtr OpType = 197 + OpStructPtrHeadOmitEmptyArrayPtr OpType = 198 + OpStructPtrHeadStringTagArrayPtr OpType = 199 + OpStructHeadMapPtr OpType = 200 + OpStructHeadOmitEmptyMapPtr OpType = 201 + OpStructHeadStringTagMapPtr OpType = 202 + OpStructPtrHeadMapPtr OpType = 203 + OpStructPtrHeadOmitEmptyMapPtr OpType = 204 + OpStructPtrHeadStringTagMapPtr OpType = 205 + OpStructHeadSlicePtr OpType = 206 + OpStructHeadOmitEmptySlicePtr OpType = 207 + OpStructHeadStringTagSlicePtr OpType = 208 + OpStructPtrHeadSlicePtr OpType = 209 + OpStructPtrHeadOmitEmptySlicePtr OpType = 210 + OpStructPtrHeadStringTagSlicePtr OpType = 211 + OpStructHeadMarshalJSONPtr OpType = 212 + OpStructHeadOmitEmptyMarshalJSONPtr OpType = 213 + OpStructHeadStringTagMarshalJSONPtr OpType = 214 + OpStructPtrHeadMarshalJSONPtr OpType = 215 + OpStructPtrHeadOmitEmptyMarshalJSONPtr OpType = 216 + OpStructPtrHeadStringTagMarshalJSONPtr OpType = 217 + OpStructHeadMarshalTextPtr OpType = 218 + OpStructHeadOmitEmptyMarshalTextPtr OpType = 219 + OpStructHeadStringTagMarshalTextPtr OpType = 220 + OpStructPtrHeadMarshalTextPtr OpType = 221 + OpStructPtrHeadOmitEmptyMarshalTextPtr OpType = 222 + OpStructPtrHeadStringTagMarshalTextPtr OpType = 223 + OpStructHeadInterfacePtr OpType = 224 + OpStructHeadOmitEmptyInterfacePtr OpType = 225 + OpStructHeadStringTagInterfacePtr OpType = 226 + OpStructPtrHeadInterfacePtr OpType = 227 + OpStructPtrHeadOmitEmptyInterfacePtr OpType = 228 + OpStructPtrHeadStringTagInterfacePtr OpType = 229 + OpStructHeadRecursivePtr OpType = 230 + OpStructHeadOmitEmptyRecursivePtr OpType = 231 + OpStructHeadStringTagRecursivePtr OpType = 232 + OpStructPtrHeadRecursivePtr OpType = 233 + OpStructPtrHeadOmitEmptyRecursivePtr OpType = 234 + OpStructPtrHeadStringTagRecursivePtr OpType = 235 + OpStructHead OpType = 236 + OpStructHeadOmitEmpty OpType = 237 + OpStructHeadStringTag OpType = 238 + OpStructPtrHead OpType = 239 + OpStructPtrHeadOmitEmpty OpType = 240 + OpStructPtrHeadStringTag OpType = 241 + OpStructFieldInt OpType = 242 + OpStructFieldOmitEmptyInt OpType = 243 + OpStructFieldStringTagInt OpType = 244 + OpStructEndInt OpType = 245 + OpStructEndOmitEmptyInt OpType = 246 + OpStructEndStringTagInt OpType = 247 + OpStructFieldUint OpType = 248 + OpStructFieldOmitEmptyUint OpType = 249 + OpStructFieldStringTagUint OpType = 250 + OpStructEndUint OpType = 251 + OpStructEndOmitEmptyUint OpType = 252 + OpStructEndStringTagUint OpType = 253 + OpStructFieldFloat32 OpType = 254 + OpStructFieldOmitEmptyFloat32 OpType = 255 + OpStructFieldStringTagFloat32 OpType = 256 + OpStructEndFloat32 OpType = 257 + OpStructEndOmitEmptyFloat32 OpType = 258 + OpStructEndStringTagFloat32 OpType = 259 + OpStructFieldFloat64 OpType = 260 + OpStructFieldOmitEmptyFloat64 OpType = 261 + OpStructFieldStringTagFloat64 OpType = 262 + OpStructEndFloat64 OpType = 263 + OpStructEndOmitEmptyFloat64 OpType = 264 + OpStructEndStringTagFloat64 OpType = 265 + OpStructFieldBool OpType = 266 + OpStructFieldOmitEmptyBool OpType = 267 + OpStructFieldStringTagBool OpType = 268 + OpStructEndBool OpType = 269 + OpStructEndOmitEmptyBool OpType = 270 + OpStructEndStringTagBool OpType = 271 + OpStructFieldString OpType = 272 + OpStructFieldOmitEmptyString OpType = 273 + OpStructFieldStringTagString OpType = 274 + OpStructEndString OpType = 275 + OpStructEndOmitEmptyString OpType = 276 + OpStructEndStringTagString OpType = 277 + OpStructFieldBytes OpType = 278 + OpStructFieldOmitEmptyBytes OpType = 279 + OpStructFieldStringTagBytes OpType = 280 + OpStructEndBytes OpType = 281 + OpStructEndOmitEmptyBytes OpType = 282 + OpStructEndStringTagBytes OpType = 283 + OpStructFieldNumber OpType = 284 + OpStructFieldOmitEmptyNumber OpType = 285 + OpStructFieldStringTagNumber OpType = 286 + OpStructEndNumber OpType = 287 + OpStructEndOmitEmptyNumber OpType = 288 + OpStructEndStringTagNumber OpType = 289 + OpStructFieldArray OpType = 290 + OpStructFieldOmitEmptyArray OpType = 291 + OpStructFieldStringTagArray OpType = 292 + OpStructEndArray OpType = 293 + OpStructEndOmitEmptyArray OpType = 294 + OpStructEndStringTagArray OpType = 295 + OpStructFieldMap OpType = 296 + OpStructFieldOmitEmptyMap OpType = 297 + OpStructFieldStringTagMap OpType = 298 + OpStructEndMap OpType = 299 + OpStructEndOmitEmptyMap OpType = 300 + OpStructEndStringTagMap OpType = 301 + OpStructFieldSlice OpType = 302 + OpStructFieldOmitEmptySlice OpType = 303 + OpStructFieldStringTagSlice OpType = 304 + OpStructEndSlice OpType = 305 + OpStructEndOmitEmptySlice OpType = 306 + OpStructEndStringTagSlice OpType = 307 + OpStructFieldStruct OpType = 308 + OpStructFieldOmitEmptyStruct OpType = 309 + OpStructFieldStringTagStruct OpType = 310 + OpStructEndStruct OpType = 311 + OpStructEndOmitEmptyStruct OpType = 312 + OpStructEndStringTagStruct OpType = 313 + OpStructFieldMarshalJSON OpType = 314 + OpStructFieldOmitEmptyMarshalJSON OpType = 315 + OpStructFieldStringTagMarshalJSON OpType = 316 + OpStructEndMarshalJSON OpType = 317 + OpStructEndOmitEmptyMarshalJSON OpType = 318 + OpStructEndStringTagMarshalJSON OpType = 319 + OpStructFieldMarshalText OpType = 320 + OpStructFieldOmitEmptyMarshalText OpType = 321 + OpStructFieldStringTagMarshalText OpType = 322 + OpStructEndMarshalText OpType = 323 + OpStructEndOmitEmptyMarshalText OpType = 324 + OpStructEndStringTagMarshalText OpType = 325 + OpStructFieldRecursive OpType = 326 + OpStructFieldOmitEmptyRecursive OpType = 327 + OpStructFieldStringTagRecursive OpType = 328 + OpStructEndRecursive OpType = 329 + OpStructEndOmitEmptyRecursive OpType = 330 + OpStructEndStringTagRecursive OpType = 331 + OpStructFieldIntString OpType = 332 + OpStructFieldOmitEmptyIntString OpType = 333 + OpStructFieldStringTagIntString OpType = 334 + OpStructEndIntString OpType = 335 + OpStructEndOmitEmptyIntString OpType = 336 + OpStructEndStringTagIntString OpType = 337 + OpStructFieldUintString OpType = 338 + OpStructFieldOmitEmptyUintString OpType = 339 + OpStructFieldStringTagUintString OpType = 340 + OpStructEndUintString OpType = 341 + OpStructEndOmitEmptyUintString OpType = 342 + OpStructEndStringTagUintString OpType = 343 + OpStructFieldIntPtr OpType = 344 + OpStructFieldOmitEmptyIntPtr OpType = 345 + OpStructFieldStringTagIntPtr OpType = 346 + OpStructEndIntPtr OpType = 347 + OpStructEndOmitEmptyIntPtr OpType = 348 + OpStructEndStringTagIntPtr OpType = 349 + OpStructFieldUintPtr OpType = 350 + OpStructFieldOmitEmptyUintPtr OpType = 351 + OpStructFieldStringTagUintPtr OpType = 352 + OpStructEndUintPtr OpType = 353 + OpStructEndOmitEmptyUintPtr OpType = 354 + OpStructEndStringTagUintPtr OpType = 355 + OpStructFieldFloat32Ptr OpType = 356 + OpStructFieldOmitEmptyFloat32Ptr OpType = 357 + OpStructFieldStringTagFloat32Ptr OpType = 358 + OpStructEndFloat32Ptr OpType = 359 + OpStructEndOmitEmptyFloat32Ptr OpType = 360 + OpStructEndStringTagFloat32Ptr OpType = 361 + OpStructFieldFloat64Ptr OpType = 362 + OpStructFieldOmitEmptyFloat64Ptr OpType = 363 + OpStructFieldStringTagFloat64Ptr OpType = 364 + OpStructEndFloat64Ptr OpType = 365 + OpStructEndOmitEmptyFloat64Ptr OpType = 366 + OpStructEndStringTagFloat64Ptr OpType = 367 + OpStructFieldBoolPtr OpType = 368 + OpStructFieldOmitEmptyBoolPtr OpType = 369 + OpStructFieldStringTagBoolPtr OpType = 370 + OpStructEndBoolPtr OpType = 371 + OpStructEndOmitEmptyBoolPtr OpType = 372 + OpStructEndStringTagBoolPtr OpType = 373 + OpStructFieldStringPtr OpType = 374 + OpStructFieldOmitEmptyStringPtr OpType = 375 + OpStructFieldStringTagStringPtr OpType = 376 + OpStructEndStringPtr OpType = 377 + OpStructEndOmitEmptyStringPtr OpType = 378 + OpStructEndStringTagStringPtr OpType = 379 + OpStructFieldBytesPtr OpType = 380 + OpStructFieldOmitEmptyBytesPtr OpType = 381 + OpStructFieldStringTagBytesPtr OpType = 382 + OpStructEndBytesPtr OpType = 383 + OpStructEndOmitEmptyBytesPtr OpType = 384 + OpStructEndStringTagBytesPtr OpType = 385 + OpStructFieldNumberPtr OpType = 386 + OpStructFieldOmitEmptyNumberPtr OpType = 387 + OpStructFieldStringTagNumberPtr OpType = 388 + OpStructEndNumberPtr OpType = 389 + OpStructEndOmitEmptyNumberPtr OpType = 390 + OpStructEndStringTagNumberPtr OpType = 391 + OpStructFieldArrayPtr OpType = 392 + OpStructFieldOmitEmptyArrayPtr OpType = 393 + OpStructFieldStringTagArrayPtr OpType = 394 + OpStructEndArrayPtr OpType = 395 + OpStructEndOmitEmptyArrayPtr OpType = 396 + OpStructEndStringTagArrayPtr OpType = 397 + OpStructFieldMapPtr OpType = 398 + OpStructFieldOmitEmptyMapPtr OpType = 399 + OpStructFieldStringTagMapPtr OpType = 400 + OpStructEndMapPtr OpType = 401 + OpStructEndOmitEmptyMapPtr OpType = 402 + OpStructEndStringTagMapPtr OpType = 403 + OpStructFieldSlicePtr OpType = 404 + OpStructFieldOmitEmptySlicePtr OpType = 405 + OpStructFieldStringTagSlicePtr OpType = 406 + OpStructEndSlicePtr OpType = 407 + OpStructEndOmitEmptySlicePtr OpType = 408 + OpStructEndStringTagSlicePtr OpType = 409 + OpStructFieldMarshalJSONPtr OpType = 410 + OpStructFieldOmitEmptyMarshalJSONPtr OpType = 411 + OpStructFieldStringTagMarshalJSONPtr OpType = 412 + OpStructEndMarshalJSONPtr OpType = 413 + OpStructEndOmitEmptyMarshalJSONPtr OpType = 414 + OpStructEndStringTagMarshalJSONPtr OpType = 415 + OpStructFieldMarshalTextPtr OpType = 416 + OpStructFieldOmitEmptyMarshalTextPtr OpType = 417 + OpStructFieldStringTagMarshalTextPtr OpType = 418 + OpStructEndMarshalTextPtr OpType = 419 + OpStructEndOmitEmptyMarshalTextPtr OpType = 420 + OpStructEndStringTagMarshalTextPtr OpType = 421 + OpStructFieldInterfacePtr OpType = 422 + OpStructFieldOmitEmptyInterfacePtr OpType = 423 + OpStructFieldStringTagInterfacePtr OpType = 424 + OpStructEndInterfacePtr OpType = 425 + OpStructEndOmitEmptyInterfacePtr OpType = 426 + OpStructEndStringTagInterfacePtr OpType = 427 + OpStructFieldRecursivePtr OpType = 428 + OpStructFieldOmitEmptyRecursivePtr OpType = 429 + OpStructFieldStringTagRecursivePtr OpType = 430 + OpStructEndRecursivePtr OpType = 431 + OpStructEndOmitEmptyRecursivePtr OpType = 432 + OpStructEndStringTagRecursivePtr OpType = 433 + OpStructField OpType = 434 + OpStructFieldOmitEmpty OpType = 435 + OpStructFieldStringTag OpType = 436 + OpStructEnd OpType = 437 + OpStructEndOmitEmpty OpType = 438 + OpStructEndStringTag OpType = 439 +) + +func (t OpType) String() string { + if int(t) >= 440 { + return "" + } + return opTypeStrings[int(t)] +} + +func (t OpType) CodeType() CodeType { + if strings.Contains(t.String(), "Struct") { + if strings.Contains(t.String(), "End") { + return CodeStructEnd + } + return CodeStructField + } + switch t { + case OpArray, OpArrayPtr: + return CodeArrayHead + case OpArrayElem: + return CodeArrayElem + case OpSlice, OpSlicePtr: + return CodeSliceHead + case OpSliceElem: + return CodeSliceElem + case OpMap, OpMapPtr: + return CodeMapHead + case OpMapKey: + return CodeMapKey + case OpMapValue: + return CodeMapValue + case OpMapEnd: + return CodeMapEnd + } + + return CodeOp +} + +func (t OpType) HeadToPtrHead() OpType { + if strings.Index(t.String(), "PtrHead") > 0 { + return t + } + + idx := strings.Index(t.String(), "Head") + if idx == -1 { + return t + } + suffix := "Ptr" + t.String()[idx+len("Head"):] + + const toPtrOffset = 3 + if strings.Contains(OpType(int(t)+toPtrOffset).String(), suffix) { + return OpType(int(t) + toPtrOffset) + } + return t +} + +func (t OpType) HeadToOmitEmptyHead() OpType { + const toOmitEmptyOffset = 1 + if strings.Contains(OpType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") { + return OpType(int(t) + toOmitEmptyOffset) + } + + return t +} + +func (t OpType) HeadToStringTagHead() OpType { + const toStringTagOffset = 2 + if strings.Contains(OpType(int(t)+toStringTagOffset).String(), "StringTag") { + return OpType(int(t) + toStringTagOffset) + } + return t +} + +func (t OpType) PtrHeadToHead() OpType { + idx := strings.Index(t.String(), "Ptr") + if idx == -1 { + return t + } + suffix := t.String()[idx+len("Ptr"):] + + const toPtrOffset = 3 + if strings.Contains(OpType(int(t)-toPtrOffset).String(), suffix) { + return OpType(int(t) - toPtrOffset) + } + return t +} + +func (t OpType) FieldToEnd() OpType { + idx := strings.Index(t.String(), "Field") + if idx == -1 { + return t + } + suffix := t.String()[idx+len("Field"):] + const toEndOffset = 3 + if strings.Contains(OpType(int(t)+toEndOffset).String(), "End"+suffix) { + return OpType(int(t) + toEndOffset) + } + return t +} + +func (t OpType) FieldToOmitEmptyField() OpType { + const toOmitEmptyOffset = 1 + if strings.Contains(OpType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") { + return OpType(int(t) + toOmitEmptyOffset) + } + return t +} + +func (t OpType) FieldToStringTagField() OpType { + const toStringTagOffset = 2 + if strings.Contains(OpType(int(t)+toStringTagOffset).String(), "StringTag") { + return OpType(int(t) + toStringTagOffset) + } + return t +} diff --git a/internal/encoder/string.go b/internal/encoder/string.go new file mode 100644 index 0000000..26da31a --- /dev/null +++ b/internal/encoder/string.go @@ -0,0 +1,637 @@ +package encoder + +import ( + "math/bits" + "reflect" + "unicode/utf8" + "unsafe" +) + +const ( + lsb = 0x0101010101010101 + msb = 0x8080808080808080 +) + +var needEscapeWithHTML = [256]bool{ + '"': true, + '&': true, + '<': true, + '>': true, + '\\': true, + 0x00: true, + 0x01: true, + 0x02: true, + 0x03: true, + 0x04: true, + 0x05: true, + 0x06: true, + 0x07: true, + 0x08: true, + 0x09: true, + 0x0a: true, + 0x0b: true, + 0x0c: true, + 0x0d: true, + 0x0e: true, + 0x0f: true, + 0x10: true, + 0x11: true, + 0x12: true, + 0x13: true, + 0x14: true, + 0x15: true, + 0x16: true, + 0x17: true, + 0x18: true, + 0x19: true, + 0x1a: true, + 0x1b: true, + 0x1c: true, + 0x1d: true, + 0x1e: true, + 0x1f: true, + /* 0x20 - 0x7f */ + 0x80: true, + 0x81: true, + 0x82: true, + 0x83: true, + 0x84: true, + 0x85: true, + 0x86: true, + 0x87: true, + 0x88: true, + 0x89: true, + 0x8a: true, + 0x8b: true, + 0x8c: true, + 0x8d: true, + 0x8e: true, + 0x8f: true, + 0x90: true, + 0x91: true, + 0x92: true, + 0x93: true, + 0x94: true, + 0x95: true, + 0x96: true, + 0x97: true, + 0x98: true, + 0x99: true, + 0x9a: true, + 0x9b: true, + 0x9c: true, + 0x9d: true, + 0x9e: true, + 0x9f: true, + 0xa0: true, + 0xa1: true, + 0xa2: true, + 0xa3: true, + 0xa4: true, + 0xa5: true, + 0xa6: true, + 0xa7: true, + 0xa8: true, + 0xa9: true, + 0xaa: true, + 0xab: true, + 0xac: true, + 0xad: true, + 0xae: true, + 0xaf: true, + 0xb0: true, + 0xb1: true, + 0xb2: true, + 0xb3: true, + 0xb4: true, + 0xb5: true, + 0xb6: true, + 0xb7: true, + 0xb8: true, + 0xb9: true, + 0xba: true, + 0xbb: true, + 0xbc: true, + 0xbd: true, + 0xbe: true, + 0xbf: true, + 0xc0: true, + 0xc1: true, + 0xc2: true, + 0xc3: true, + 0xc4: true, + 0xc5: true, + 0xc6: true, + 0xc7: true, + 0xc8: true, + 0xc9: true, + 0xca: true, + 0xcb: true, + 0xcc: true, + 0xcd: true, + 0xce: true, + 0xcf: true, + 0xd0: true, + 0xd1: true, + 0xd2: true, + 0xd3: true, + 0xd4: true, + 0xd5: true, + 0xd6: true, + 0xd7: true, + 0xd8: true, + 0xd9: true, + 0xda: true, + 0xdb: true, + 0xdc: true, + 0xdd: true, + 0xde: true, + 0xdf: true, + 0xe0: true, + 0xe1: true, + 0xe2: true, + 0xe3: true, + 0xe4: true, + 0xe5: true, + 0xe6: true, + 0xe7: true, + 0xe8: true, + 0xe9: true, + 0xea: true, + 0xeb: true, + 0xec: true, + 0xed: true, + 0xee: true, + 0xef: true, + 0xf0: true, + 0xf1: true, + 0xf2: true, + 0xf3: true, + 0xf4: true, + 0xf5: true, + 0xf6: true, + 0xf7: true, + 0xf8: true, + 0xf9: true, + 0xfa: true, + 0xfb: true, + 0xfc: true, + 0xfd: true, + 0xfe: true, + 0xff: true, +} + +var needEscape = [256]bool{ + '"': true, + '\\': true, + 0x00: true, + 0x01: true, + 0x02: true, + 0x03: true, + 0x04: true, + 0x05: true, + 0x06: true, + 0x07: true, + 0x08: true, + 0x09: true, + 0x0a: true, + 0x0b: true, + 0x0c: true, + 0x0d: true, + 0x0e: true, + 0x0f: true, + 0x10: true, + 0x11: true, + 0x12: true, + 0x13: true, + 0x14: true, + 0x15: true, + 0x16: true, + 0x17: true, + 0x18: true, + 0x19: true, + 0x1a: true, + 0x1b: true, + 0x1c: true, + 0x1d: true, + 0x1e: true, + 0x1f: true, + /* 0x20 - 0x7f */ + 0x80: true, + 0x81: true, + 0x82: true, + 0x83: true, + 0x84: true, + 0x85: true, + 0x86: true, + 0x87: true, + 0x88: true, + 0x89: true, + 0x8a: true, + 0x8b: true, + 0x8c: true, + 0x8d: true, + 0x8e: true, + 0x8f: true, + 0x90: true, + 0x91: true, + 0x92: true, + 0x93: true, + 0x94: true, + 0x95: true, + 0x96: true, + 0x97: true, + 0x98: true, + 0x99: true, + 0x9a: true, + 0x9b: true, + 0x9c: true, + 0x9d: true, + 0x9e: true, + 0x9f: true, + 0xa0: true, + 0xa1: true, + 0xa2: true, + 0xa3: true, + 0xa4: true, + 0xa5: true, + 0xa6: true, + 0xa7: true, + 0xa8: true, + 0xa9: true, + 0xaa: true, + 0xab: true, + 0xac: true, + 0xad: true, + 0xae: true, + 0xaf: true, + 0xb0: true, + 0xb1: true, + 0xb2: true, + 0xb3: true, + 0xb4: true, + 0xb5: true, + 0xb6: true, + 0xb7: true, + 0xb8: true, + 0xb9: true, + 0xba: true, + 0xbb: true, + 0xbc: true, + 0xbd: true, + 0xbe: true, + 0xbf: true, + 0xc0: true, + 0xc1: true, + 0xc2: true, + 0xc3: true, + 0xc4: true, + 0xc5: true, + 0xc6: true, + 0xc7: true, + 0xc8: true, + 0xc9: true, + 0xca: true, + 0xcb: true, + 0xcc: true, + 0xcd: true, + 0xce: true, + 0xcf: true, + 0xd0: true, + 0xd1: true, + 0xd2: true, + 0xd3: true, + 0xd4: true, + 0xd5: true, + 0xd6: true, + 0xd7: true, + 0xd8: true, + 0xd9: true, + 0xda: true, + 0xdb: true, + 0xdc: true, + 0xdd: true, + 0xde: true, + 0xdf: true, + 0xe0: true, + 0xe1: true, + 0xe2: true, + 0xe3: true, + 0xe4: true, + 0xe5: true, + 0xe6: true, + 0xe7: true, + 0xe8: true, + 0xe9: true, + 0xea: true, + 0xeb: true, + 0xec: true, + 0xed: true, + 0xee: true, + 0xef: true, + 0xf0: true, + 0xf1: true, + 0xf2: true, + 0xf3: true, + 0xf4: true, + 0xf5: true, + 0xf6: true, + 0xf7: true, + 0xf8: true, + 0xf9: true, + 0xfa: true, + 0xfb: true, + 0xfc: true, + 0xfd: true, + 0xfe: true, + 0xff: true, +} + +var hex = "0123456789abcdef" + +// escapeIndex finds the index of the first char in `s` that requires escaping. +// A char requires escaping if it's outside of the range of [0x20, 0x7F] or if +// it includes a double quote or backslash. +// If no chars in `s` require escaping, the return value is -1. +func escapeIndex(s string) int { + chunks := stringToUint64Slice(s) + for _, n := range chunks { + // combine masks before checking for the MSB of each byte. We include + // `n` in the mask to check whether any of the *input* byte MSBs were + // set (i.e. the byte was outside the ASCII range). + mask := n | below(n, 0x20) | contains(n, '"') | contains(n, '\\') + if (mask & msb) != 0 { + return bits.TrailingZeros64(mask&msb) / 8 + } + } + + valLen := len(s) + for i := len(chunks) * 8; i < valLen; i++ { + if needEscape[s[i]] { + return i + } + } + + return -1 +} + +// below return a mask that can be used to determine if any of the bytes +// in `n` are below `b`. If a byte's MSB is set in the mask then that byte was +// below `b`. The result is only valid if `b`, and each byte in `n`, is below +// 0x80. +func below(n uint64, b byte) uint64 { + return n - expand(b) +} + +// contains returns a mask that can be used to determine if any of the +// bytes in `n` are equal to `b`. If a byte's MSB is set in the mask then +// that byte is equal to `b`. The result is only valid if `b`, and each +// byte in `n`, is below 0x80. +func contains(n uint64, b byte) uint64 { + return (n ^ expand(b)) - lsb +} + +// expand puts the specified byte into each of the 8 bytes of a uint64. +func expand(b byte) uint64 { + return lsb * uint64(b) +} + +//nolint:govet +func stringToUint64Slice(s string) []uint64 { + return *(*[]uint64)(unsafe.Pointer(&reflect.SliceHeader{ + Data: ((*reflect.StringHeader)(unsafe.Pointer(&s))).Data, + Len: len(s) / 8, + Cap: len(s) / 8, + })) +} + +func AppendEscapedString(buf []byte, s string) []byte { + valLen := len(s) + if valLen == 0 { + return append(buf, `""`...) + } + buf = append(buf, '"') + var ( + i, j int + ) + if valLen >= 8 { + chunks := stringToUint64Slice(s) + for _, n := range chunks { + // combine masks before checking for the MSB of each byte. We include + // `n` in the mask to check whether any of the *input* byte MSBs were + // set (i.e. the byte was outside the ASCII range). + mask := n | (n - (lsb * 0x20)) | + ((n ^ (lsb * '"')) - lsb) | + ((n ^ (lsb * '\\')) - lsb) | + ((n ^ (lsb * '<')) - lsb) | + ((n ^ (lsb * '>')) - lsb) | + ((n ^ (lsb * '&')) - lsb) + if (mask & msb) != 0 { + j = bits.TrailingZeros64(mask&msb) / 8 + goto ESCAPE_END + } + } + for i := len(chunks) * 8; i < valLen; i++ { + if needEscapeWithHTML[s[i]] { + j = i + goto ESCAPE_END + } + } + // no found any escape characters. + return append(append(buf, s...), '"') + } +ESCAPE_END: + for j < valLen { + c := s[j] + + if !needEscapeWithHTML[c] { + // fast path: most of the time, printable ascii characters are used + j++ + continue + } + + switch c { + case '\\', '"': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', c) + i = j + 1 + j = j + 1 + continue + + case '\n': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'n') + i = j + 1 + j = j + 1 + continue + + case '\r': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'r') + i = j + 1 + j = j + 1 + continue + + case '\t': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 't') + i = j + 1 + j = j + 1 + continue + + case '<', '>', '&': + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + // This encodes bytes < 0x20 except for \t, \n and \r. + if c < 0x20 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + r, size := utf8.DecodeRuneInString(s[j:]) + + if r == utf8.RuneError && size == 1 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\ufffd`...) + i = j + size + j = j + size + continue + } + + switch r { + case '\u2028', '\u2029': + // U+2028 is LINE SEPARATOR. + // U+2029 is PARAGRAPH SEPARATOR. + // They are both technically valid characters in JSON strings, + // but don't work in JSONP, which has to be evaluated as JavaScript, + // and can lead to security holes there. It is valid JSON to + // escape them, so we do so unconditionally. + // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. + buf = append(buf, s[i:j]...) + buf = append(buf, `\u202`...) + buf = append(buf, hex[r&0xF]) + i = j + size + j = j + size + continue + } + + j += size + } + + return append(append(buf, s[i:]...), '"') +} + +func AppendString(buf []byte, s string) []byte { + valLen := len(s) + if valLen == 0 { + return append(buf, `""`...) + } + buf = append(buf, '"') + var escapeIdx int + if valLen >= 8 { + if escapeIdx = escapeIndex(s); escapeIdx < 0 { + return append(append(buf, s...), '"') + } + } + + i := 0 + j := escapeIdx + for j < valLen { + c := s[j] + + if c >= 0x20 && c <= 0x7f && c != '\\' && c != '"' { + // fast path: most of the time, printable ascii characters are used + j++ + continue + } + + switch c { + case '\\', '"': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', c) + i = j + 1 + j = j + 1 + continue + + case '\n': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'n') + i = j + 1 + j = j + 1 + continue + + case '\r': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'r') + i = j + 1 + j = j + 1 + continue + + case '\t': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 't') + i = j + 1 + j = j + 1 + continue + + case '<', '>', '&': + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + // This encodes bytes < 0x20 except for \t, \n and \r. + if c < 0x20 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + r, size := utf8.DecodeRuneInString(s[j:]) + + if r == utf8.RuneError && size == 1 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\ufffd`...) + i = j + size + j = j + size + continue + } + + switch r { + case '\u2028', '\u2029': + // U+2028 is LINE SEPARATOR. + // U+2029 is PARAGRAPH SEPARATOR. + // They are both technically valid characters in JSON strings, + // but don't work in JSONP, which has to be evaluated as JavaScript, + // and can lead to security holes there. It is valid JSON to + // escape them, so we do so unconditionally. + // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. + buf = append(buf, s[i:j]...) + buf = append(buf, `\u202`...) + buf = append(buf, hex[r&0xF]) + i = j + size + j = j + size + continue + } + + j += size + } + + return append(append(buf, s[i:]...), '"') +} diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go new file mode 100644 index 0000000..e7fddd4 --- /dev/null +++ b/internal/encoder/vm/vm.go @@ -0,0 +1,3759 @@ +package json + +import ( + "fmt" + "math" + "reflect" + "sort" + "strings" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/encoder/compiler" + "github.com/goccy/go-json/internal/runtime" +) + +const uintptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const + +var ( + load = encoder.Load + store = encoder.Store + loadAndStoreNPtr = encoder.LoadAndStoreNPtr + ptrToPtr = encoder.PtrToPtr + ptrToNPtr = encoder.PtrToNPtr + ptrToUnsafePtr = encoder.PtrToUnsafePtr + ptrToInterface = encoder.PtrToInterface + ptrToUint64 = encoder.PtrToUint64 + ptrToFloat32 = encoder.PtrToFloat32 + ptrToFloat64 = encoder.PtrToFloat64 + ptrToString = encoder.PtrToString + ptrToBool = encoder.PtrToBool + ptrToBytes = encoder.PtrToBytes + ptrToNumber = encoder.PtrToNumber + ptrToSlice = encoder.PtrToSlice + appendInt = encoder.AppendInt + appendUint = encoder.AppendUint + appendFloat32 = encoder.AppendFloat32 + appendFloat64 = encoder.AppendFloat64 + appendString = encoder.AppendString + appendBool = encoder.AppendBool + appendByteSlice = encoder.AppendByteSlice + appendNumber = encoder.AppendNumber + appendMarshalJSON = encoder.AppendMarshalJSON + appendMarshalText = encoder.AppendMarshalText + appendNull = encoder.AppendNull + appendComma = encoder.AppendComma + appendStructEnd = encoder.AppendStructEnd + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + errMarshalerWithCode = encoder.ErrMarshalerWithCode + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen +) + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) { + recursiveLevel := 0 + ptrOffset := uintptr(0) + ctxptr := ctx.Ptr() + code := codeSet.Code + + for { + switch code.Op { + default: + return nil, fmt.Errorf("encoder: opcode %s has not been implemented", code.Op) + case encoder.OpPtr: + p := load(ctxptr, code.Idx) + code = code.Next + store(ctxptr, code.Idx, ptrToPtr(p)) + case encoder.OpIntPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpInt: + b = appendInt(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(b) + code = code.Next + case encoder.OpUintPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpUint: + b = appendUint(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpUintString: + b = append(b, '"') + b = appendUint(b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpFloat32Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpFloat32: + b = appendFloat32(b, ptrToFloat32(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpFloat64Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpFloat64: + v := ptrToFloat64(load(ctxptr, code.Idx)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, encoder.ErrUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStringPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpString: + b = appendString(b, ptrToString(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpBoolPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpBool: + b = appendBool(b, ptrToBool(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpBytesPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpBytes: + b = appendByteSlice(b, ptrToBytes(load(ctxptr, code.Idx))) + b = appendComma(b) + code = code.Next + case encoder.OpNumberPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpNumber: + bb, err := appendNumber(b, ptrToNumber(load(ctxptr, code.Idx))) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpInterfacePtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + for _, seen := range ctx.SeenPtr { + if p == seen { + return nil, errUnsupportedValue(code, p) + } + } + ctx.SeenPtr = append(ctx.SeenPtr, p) + iface := (*emptyInterface)(ptrToUnsafePtr(p)) + if iface.ptr == nil { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) + ifaceCodeSet, err := compiler.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + if err != nil { + return nil, err + } + + totalLength := uintptr(codeSet.CodeLength) + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + + newLen := offsetNum + totalLength + nextTotalLength + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + oldPtrs := ctx.Ptrs + + newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:] + newPtrs[0] = uintptr(iface.ptr) + + ctx.Ptrs = newPtrs + + bb, err := Run(ctx, b, ifaceCodeSet, opt) + if err != nil { + return nil, err + } + + ctx.Ptrs = oldPtrs + ctxptr = ctx.Ptr() + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + b = bb + code = code.Next + case encoder.OpMarshalJSONPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpMarshalTextPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + b = append(b, `""`...) + b = appendComma(b) + code = code.Next + break + } + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpSlicePtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpSlice: + p := load(ctxptr, code.Idx) + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(slice.Len)) + if slice.Len > 0 { + b = append(b, '[') + code = code.Next + store(ctxptr, code.Idx, uintptr(slice.Data)) + } else { + b = append(b, '[', ']', ',') + code = code.End.Next + } + case encoder.OpSliceElem: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if idx < length { + store(ctxptr, code.ElemIdx, idx) + data := load(ctxptr, code.HeadIdx) + size := code.Size + code = code.Next + store(ctxptr, code.Idx, data+idx*size) + } else { + last := len(b) - 1 + b[last] = ']' + b = appendComma(b) + code = code.End.Next + } + case encoder.OpArrayPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpArray: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + if code.Length > 0 { + b = append(b, '[') + store(ctxptr, code.ElemIdx, 0) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + b = append(b, '[', ']', ',') + code = code.End.Next + } + case encoder.OpArrayElem: + idx := load(ctxptr, code.ElemIdx) + idx++ + if idx < code.Length { + store(ctxptr, code.ElemIdx, idx) + p := load(ctxptr, code.HeadIdx) + size := code.Size + code = code.Next + store(ctxptr, code.Idx, p+idx*size) + } else { + last := len(b) - 1 + b[last] = ']' + b = appendComma(b) + code = code.End.Next + } + case encoder.OpMapPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpMap: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.End.Next + break + } + uptr := ptrToUnsafePtr(p) + mlen := maplen(uptr) + if mlen <= 0 { + b = append(b, '{', '}', ',') + code = code.End.Next + break + } + b = append(b, '{') + iter := mapiterinit(code.Type, uptr) + ctx.KeepRefs = append(ctx.KeepRefs, iter) + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(mlen)) + store(ctxptr, code.MapIter, uintptr(iter)) + if (opt & encoder.UnorderedMapOption) == 0 { + mapCtx := encoder.NewMapContext(mlen) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx))) + } + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if (opt & encoder.UnorderedMapOption) != 0 { + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + last := len(b) - 1 + b[last] = '}' + b = appendComma(b) + code = code.End.Next + } + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + if (opt & encoder.UnorderedMapOption) != 0 { + last := len(b) - 1 + b[last] = ':' + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + } + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + value := mapitervalue(iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map. + length := int(load(ctxptr, code.Length)) + ptr := load(ctxptr, code.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + pos := mapCtx.Pos + for i := 0; i < length; i++ { + startKey := pos[i*2] + startValue := pos[i*2+1] + var endValue int + if i+1 < length { + endValue = pos[i*2+2] + } else { + endValue = len(b) + } + mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{ + Key: b[startKey:startValue], + Value: b[startValue:endValue], + }) + } + sort.Sort(mapCtx.Slice) + buf := mapCtx.Buf + for _, item := range mapCtx.Slice.Items { + buf = append(buf, item.Key...) + buf[len(buf)-1] = ':' + buf = append(buf, item.Value...) + } + buf[len(buf)-1] = '}' + buf = append(buf, ',') + b = b[:pos[0]] + b = append(b, buf...) + mapCtx.Buf = buf + encoder.ReleaseMapContext(mapCtx) + code = code.Next + case encoder.OpStructFieldRecursivePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructFieldRecursive: + ptr := load(ctxptr, code.Idx) + if ptr != 0 { + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if ptr == seen { + return nil, errUnsupportedValue(code, ptr) + } + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, ptr) + c := code.Jmp.Code + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += code.Jmp.CurLen * uintptrSize + + newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + store(ctxptr, c.Idx, ptr) + store(ctxptr, c.End.Next.Idx, oldOffset) + store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + code = c + recursiveLevel++ + case encoder.OpStructFieldRecursiveEnd: + recursiveLevel-- + + // restore ctxptr + offset := load(ctxptr, code.Idx) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpStructPtrHead: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHead: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if !code.AnonymousKey { + b = append(b, code.Key...) + } + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmpty: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + if p == 0 || (ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr")) { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadStringTag: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTag: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Indirect || code.Next.Op == encoder.OpStructEnd) { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadInt: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyInt: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + b = appendInt(b, u64, code) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagInt: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadIntPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagIntPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadUint: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUint: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + b = appendUint(b, u64, code) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagUint: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadUintPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagUintPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat32: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToFloat32(p + code.Offset) + if v == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + b = appendFloat32(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagFloat32: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat32Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagFloat32Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat64: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToFloat64(p + code.Offset) + if v == 0 { + code = code.NextField + } else { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagFloat64: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadFloat64Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagFloat64Ptr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadString: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyString: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToString(p + code.Offset) + if v == "" { + code = code.NextField + } else { + b = append(b, code.Key...) + b = appendString(b, v) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagString: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagString: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendString(b, ptrToString(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagStringPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBool: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBool: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToBool(p + code.Offset) + if v { + b = append(b, code.Key...) + b = appendBool(b, v) + b = appendComma(b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadStringTagBool: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBoolPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagBoolPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBytes: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytes: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToBytes(p + code.Offset) + if v == nil { + code = code.NextField + } else { + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagBytes: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadBytesPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytesPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagBytesPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadNumber: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumber: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + v := ptrToNumber(p + code.Offset) + if v == "" { + code = code.NextField + } else { + b = append(b, code.Key...) + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + } + case encoder.OpStructPtrHeadStringTagNumber: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadStringTagNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadNumberPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructPtrHeadStringTagNumberPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadArray, encoder.OpStructPtrHeadStringTagArray, + encoder.OpStructPtrHeadSlice, encoder.OpStructPtrHeadStringTagSlice: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadArray, encoder.OpStructHeadStringTagArray, + encoder.OpStructHeadSlice, encoder.OpStructHeadStringTagSlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyArray: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptyArray: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptySlice: + if code.Indirect { + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + } + fallthrough + case encoder.OpStructHeadOmitEmptySlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + p += code.Offset + slice := ptrToSlice(p) + if slice.Data == nil { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadArrayPtr, encoder.OpStructPtrHeadStringTagArrayPtr, + encoder.OpStructPtrHeadSlicePtr, encoder.OpStructPtrHeadStringTagSlicePtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadArrayPtr, encoder.OpStructHeadStringTagArrayPtr, + encoder.OpStructHeadSlicePtr, encoder.OpStructHeadStringTagSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + } else { + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyArrayPtr, encoder.OpStructPtrHeadOmitEmptySlicePtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyArrayPtr, encoder.OpStructHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMap, encoder.OpStructPtrHeadStringTagMap: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMap, encoder.OpStructHeadStringTagMap: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if p != 0 && code.Indirect { + p = ptrToPtr(p + code.Offset) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyMap: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p != 0 && code.Indirect { + p = ptrToPtr(p + code.Offset) + } + if maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMapPtr, encoder.OpStructPtrHeadStringTagMapPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMapPtr, encoder.OpStructHeadStringTagMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + break + } + p = ptrToPtr(p + code.Offset) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.NextField + } else { + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyMapPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p == 0 { + code = code.NextField + break + } + p = ptrToPtr(p + code.Offset) + if p == 0 { + code = code.NextField + } else { + if code.Indirect { + p = ptrToNPtr(p, code.PtrNum) + } + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMarshalJSON: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringTagMarshalJSON: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSON: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + code = code.NextField + } else { + b = append(b, code.Key...) + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalJSONPtr, encoder.OpStructPtrHeadStringTagMarshalJSONPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMarshalJSONPtr, encoder.OpStructHeadStringTagMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSONPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalText: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadStringTagMarshalText: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadStringTagMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalText: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + if code.Type.Kind() == reflect.Ptr { + if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p + code.Offset) + } + } + if p == 0 && code.Nilcheck { + code = code.NextField + } else { + b = append(b, code.Key...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalTextPtr, encoder.OpStructPtrHeadStringTagMarshalTextPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadMarshalTextPtr, encoder.OpStructHeadStringTagMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if !code.AnonymousHead { + b = append(b, '{') + } + b = append(b, code.Key...) + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalTextPtr: + loadAndStoreNPtr(ctxptr, code.Idx, code.PtrNum) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && code.Indirect { + if !code.AnonymousHead { + b = appendNull(b) + b = appendComma(b) + } + code = code.End.Next + break + } + if code.Indirect { + p = ptrToNPtr(p+code.Offset, code.PtrNum) + } + if !code.AnonymousHead { + b = append(b, '{') + } + if p == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + b = appendComma(b) + code = code.Next + } + case encoder.OpStructField: + if !code.AnonymousKey { + b = append(b, code.Key...) + } + p := load(ctxptr, code.HeadIdx) + code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmpty: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if ptrToPtr(p) == 0 && strings.Contains(code.Next.Op.String(), "Ptr") { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldStringTag: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyInt: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.Key...) + b = appendInt(b, u64, code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldIntPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.Key...) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUint: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.Key...) + b = appendUint(b, u64, code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldUintPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p), code) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.Key...) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat32(p + code.Offset) + if v != 0 { + b = append(b, code.Key...) + b = appendFloat32(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat32Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.Key...) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat64: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldFloat64Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendComma(b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + b = append(b, code.Key...) + if p == 0 { + b = appendNull(b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyString: + p := load(ctxptr, code.HeadIdx) + v := ptrToString(p + code.Offset) + if v != "" { + b = append(b, code.Key...) + b = appendString(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldStringPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendString(b, ptrToString(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagStringPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBool: + p := load(ctxptr, code.HeadIdx) + v := ptrToBool(p + code.Offset) + if v { + b = append(b, code.Key...) + b = appendBool(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBoolPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBoolPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBytes: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + if len(v) > 0 { + b = append(b, code.Key...) + b = appendByteSlice(b, v) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + b = append(b, code.Key...) + b = appendByteSlice(b, v) + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldBytesPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytesPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendComma(b) + } + code = code.Next + case encoder.OpStructFieldStringTagBytesPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumber: + p := load(ctxptr, code.HeadIdx) + v := ptrToNumber(p + code.Offset) + if v != "" { + b = append(b, code.Key...) + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldStringTagNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldNumberPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldStringTagNumberPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldMarshalJSON, encoder.OpStructFieldStringTagMarshalJSON: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSON: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + code = code.NextField + break + } + b = append(b, code.Key...) + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldMarshalJSONPtr, encoder.OpStructFieldStringTagMarshalJSONPtr: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldMarshalText, encoder.OpStructFieldStringTagMarshalText: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalText: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + if code.Type.Kind() == reflect.Ptr { + p = ptrToPtr(p) + } + if p == 0 && code.Nilcheck { + code = code.NextField + break + } + b = append(b, code.Key...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + code = code.Next + case encoder.OpStructFieldMarshalTextPtr, encoder.OpStructFieldStringTagMarshalTextPtr: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + if err != nil { + return nil, err + } + b = appendComma(bb) + } + code = code.Next + case encoder.OpStructFieldArray, encoder.OpStructFieldStringTagArray: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArray: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldArrayPtr, encoder.OpStructFieldStringTagArrayPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArrayPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldSlice, encoder.OpStructFieldStringTagSlice: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlice: + p := load(ctxptr, code.HeadIdx) + p += code.Offset + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldSlicePtr, encoder.OpStructFieldStringTagSlicePtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlicePtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldMap, encoder.OpStructFieldStringTagMap: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMap: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldMapPtr, encoder.OpStructFieldStringTagMapPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMapPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToPtr(p + code.Offset) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + if p != 0 { + b = append(b, code.Key...) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldStruct: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p += code.Offset + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructEnd: + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + } else { + b = append(b, '}') + } + b = appendComma(b) + code = code.Next + case encoder.OpStructAnonymousEnd: + code = code.Next + case encoder.OpStructEndInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyInt: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.Key...) + b = appendInt(b, u64, code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagInt: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendInt(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndIntPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendInt(b, ptrToUint64(p), code) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendInt(b, ptrToUint64(p), code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagIntPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendInt(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyUint: + p := load(ctxptr, code.HeadIdx) + u64 := ptrToUint64(p + code.Offset) + v := u64 & code.Mask + if v != 0 { + b = append(b, code.Key...) + b = appendUint(b, u64, code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagUint: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendUint(b, ptrToUint64(p+code.Offset), code) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndUintPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendUint(b, ptrToUint64(p), code) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendUint(b, ptrToUint64(p), code) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagUintPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendUint(b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat32(p + code.Offset) + if v != 0 { + b = append(b, code.Key...) + b = appendFloat32(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat32: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p+code.Offset)) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat32Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendFloat32(b, ptrToFloat32(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendFloat32(b, ptrToFloat32(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat32Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendFloat32(b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat64: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = appendFloat64(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat64: + p := load(ctxptr, code.HeadIdx) + v := ptrToFloat64(p + code.Offset) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, code.Key...) + b = append(b, '"') + b = appendFloat64(b, v) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndFloat64Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + b = appendStructEnd(b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64Ptr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagFloat64Ptr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(b, v) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendString(b, ptrToString(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyString: + p := load(ctxptr, code.HeadIdx) + v := ptrToString(p + code.Offset) + if v != "" { + b = append(b, code.Key...) + b = appendString(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagString: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + s := ptrToString(p + code.Offset) + b = appendString(b, string(appendString([]byte{}, s))) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndStringPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendString(b, ptrToString(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendString(b, ptrToString(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagStringPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + v := ptrToString(p) + b = appendString(b, string(appendString([]byte{}, v))) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBool: + p := load(ctxptr, code.HeadIdx) + v := ptrToBool(p + code.Offset) + if v { + b = append(b, code.Key...) + b = appendBool(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBool: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + b = appendBool(b, ptrToBool(p+code.Offset)) + b = append(b, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBoolPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendBool(b, ptrToBool(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendBool(b, ptrToBool(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBoolPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendBool(b, ptrToBool(p)) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBytes: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p+code.Offset)) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + if len(v) > 0 { + b = append(b, code.Key...) + b = appendByteSlice(b, v) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBytes: + p := load(ctxptr, code.HeadIdx) + v := ptrToBytes(p + code.Offset) + b = append(b, code.Key...) + b = appendByteSlice(b, v) + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndBytesPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = appendByteSlice(b, ptrToBytes(p)) + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytesPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + b = appendByteSlice(b, ptrToBytes(p)) + b = appendStructEnd(b) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagBytesPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + b = appendByteSlice(b, ptrToBytes(p)) + b = append(b, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = appendStructEnd(bb) + code = code.Next + case encoder.OpStructEndOmitEmptyNumber: + p := load(ctxptr, code.HeadIdx) + v := ptrToNumber(p + code.Offset) + if v != "" { + b = append(b, code.Key...) + bb, err := appendNumber(b, v) + if err != nil { + return nil, err + } + b = appendStructEnd(bb) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagNumber: + p := load(ctxptr, code.HeadIdx) + b = append(b, code.Key...) + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p+code.Offset)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndNumberPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtr: + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p != 0 { + b = append(b, code.Key...) + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendStructEnd(bb) + } else { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + b = appendComma(b) + } else { + b = appendStructEnd(b) + } + } + code = code.Next + case encoder.OpStructEndStringTagNumberPtr: + b = append(b, code.Key...) + p := load(ctxptr, code.HeadIdx) + p = ptrToNPtr(p+code.Offset, code.PtrNum) + if p == 0 { + b = appendNull(b) + } else { + b = append(b, '"') + bb, err := appendNumber(b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendStructEnd(b) + code = code.Next + case encoder.OpEnd: + goto END + } + } +END: + return b, nil +} diff --git a/internal/runtime/type.go b/internal/runtime/type.go new file mode 100644 index 0000000..fd425f7 --- /dev/null +++ b/internal/runtime/type.go @@ -0,0 +1,9 @@ +package runtime + +import "unsafe" + +type SliceHeader struct { + Data unsafe.Pointer + Len int + Cap int +}