forked from mirror/go-json
Merge pull request #77 from goccy/feature/optimize-struct-end
Optimize StructEnd operation
This commit is contained in:
commit
cc45937ab1
|
@ -22,10 +22,51 @@ type opType struct {
|
||||||
HeadToOmitEmptyHead func() string
|
HeadToOmitEmptyHead func() string
|
||||||
HeadToStringTagHead func() string
|
HeadToStringTagHead func() string
|
||||||
PtrHeadToHead func() string
|
PtrHeadToHead func() string
|
||||||
|
FieldToEnd func() string
|
||||||
FieldToOmitEmptyField func() string
|
FieldToOmitEmptyField func() string
|
||||||
FieldToStringTagField func() string
|
FieldToStringTagField func() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t opType) IsEscaped() bool {
|
||||||
|
return t.Op != t.Escaped()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t opType) IsHeadToPtrHead() bool {
|
||||||
|
return t.Op != t.HeadToPtrHead()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t opType) IsHeadToNPtrHead() bool {
|
||||||
|
return t.Op != t.HeadToNPtrHead()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t opType) IsHeadToAnonymousHead() bool {
|
||||||
|
return t.Op != t.HeadToAnonymousHead()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t opType) IsHeadToOmitEmptyHead() bool {
|
||||||
|
return t.Op != t.HeadToOmitEmptyHead()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t opType) IsHeadToStringTagHead() bool {
|
||||||
|
return t.Op != t.HeadToStringTagHead()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t opType) IsPtrHeadToHead() bool {
|
||||||
|
return t.Op != t.PtrHeadToHead()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t opType) IsFieldToEnd() bool {
|
||||||
|
return t.Op != t.FieldToEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t opType) IsFieldToOmitEmptyField() bool {
|
||||||
|
return t.Op != t.FieldToOmitEmptyField()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t opType) IsFieldToStringTagField() bool {
|
||||||
|
return t.Op != t.FieldToStringTagField()
|
||||||
|
}
|
||||||
|
|
||||||
func createOpType(op, code string) opType {
|
func createOpType(op, code string) opType {
|
||||||
return opType{
|
return opType{
|
||||||
Op: op,
|
Op: op,
|
||||||
|
@ -38,6 +79,7 @@ func createOpType(op, code string) opType {
|
||||||
HeadToOmitEmptyHead: func() string { return op },
|
HeadToOmitEmptyHead: func() string { return op },
|
||||||
HeadToStringTagHead: func() string { return op },
|
HeadToStringTagHead: func() string { return op },
|
||||||
PtrHeadToHead: func() string { return op },
|
PtrHeadToHead: func() string { return op },
|
||||||
|
FieldToEnd: func() string { return op },
|
||||||
FieldToOmitEmptyField: func() string { return op },
|
FieldToOmitEmptyField: func() string { return op },
|
||||||
FieldToStringTagField: func() string { return op },
|
FieldToStringTagField: func() string { return op },
|
||||||
}
|
}
|
||||||
|
@ -64,8 +106,12 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t opType) String() string {
|
func (t opType) String() string {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return t.toNotIndent().String() + "Indent"
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
{{- range $type := .OpTypes }}
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
case op{{ $type.Op }}:
|
case op{{ $type.Op }}:
|
||||||
return "{{ $type.Op }}"
|
return "{{ $type.Op }}"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
@ -74,8 +120,12 @@ func (t opType) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t opType) codeType() codeType {
|
func (t opType) codeType() codeType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return t.toNotIndent().codeType()
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
{{- range $type := .OpTypes }}
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
case op{{ $type.Op }}:
|
case op{{ $type.Op }}:
|
||||||
return code{{ $type.Code }}
|
return code{{ $type.Code }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
@ -83,101 +133,175 @@ func (t opType) codeType() codeType {
|
||||||
return codeOp
|
return codeOp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t opType) toIndent() opType {
|
func (t opType) toNotIndent() opType {
|
||||||
switch t {
|
if int(t) >= {{ .OpLen }} {
|
||||||
{{- range $type := .OpTypes }}
|
return opType(int(t) - {{ .OpLen }})
|
||||||
case op{{ $type.Op }}:
|
|
||||||
return op{{ call $type.Indent }}
|
|
||||||
{{- end }}
|
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t opType) toIndent() opType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
return opType(int(t) + {{ .OpLen }})
|
||||||
|
}
|
||||||
|
|
||||||
func (t opType) toEscaped() opType {
|
func (t opType) toEscaped() opType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return opType(int(t.toNotIndent().toEscaped()) + {{ .OpLen }})
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
{{- range $type := .OpTypes }}
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
|
{{- if $type.IsEscaped }}
|
||||||
case op{{ $type.Op }}:
|
case op{{ $type.Op }}:
|
||||||
return op{{ call $type.Escaped }}
|
return op{{ call $type.Escaped }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t opType) headToPtrHead() opType {
|
func (t opType) headToPtrHead() opType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return opType(int(t.toNotIndent().headToPtrHead()) + {{ .OpLen }})
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
{{- range $type := .OpTypes }}
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
|
{{- if $type.IsHeadToPtrHead }}
|
||||||
case op{{ $type.Op }}:
|
case op{{ $type.Op }}:
|
||||||
return op{{ call $type.HeadToPtrHead }}
|
return op{{ call $type.HeadToPtrHead }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t opType) headToNPtrHead() opType {
|
func (t opType) headToNPtrHead() opType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return opType(int(t.toNotIndent().headToNPtrHead()) + {{ .OpLen }})
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
{{- range $type := .OpTypes }}
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
|
{{- if $type.IsHeadToNPtrHead }}
|
||||||
case op{{ $type.Op }}:
|
case op{{ $type.Op }}:
|
||||||
return op{{ call $type.HeadToNPtrHead }}
|
return op{{ call $type.HeadToNPtrHead }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t opType) headToAnonymousHead() opType {
|
func (t opType) headToAnonymousHead() opType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return opType(int(t.toNotIndent().headToAnonymousHead()) + {{ .OpLen }})
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
{{- range $type := .OpTypes }}
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
|
{{- if $type.IsHeadToAnonymousHead }}
|
||||||
case op{{ $type.Op }}:
|
case op{{ $type.Op }}:
|
||||||
return op{{ call $type.HeadToAnonymousHead }}
|
return op{{ call $type.HeadToAnonymousHead }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t opType) headToOmitEmptyHead() opType {
|
func (t opType) headToOmitEmptyHead() opType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return opType(int(t.toNotIndent().headToOmitEmptyHead()) + {{ .OpLen }})
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
{{- range $type := .OpTypes }}
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
|
{{- if $type.IsHeadToOmitEmptyHead }}
|
||||||
case op{{ $type.Op }}:
|
case op{{ $type.Op }}:
|
||||||
return op{{ call $type.HeadToOmitEmptyHead }}
|
return op{{ call $type.HeadToOmitEmptyHead }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t opType) headToStringTagHead() opType {
|
func (t opType) headToStringTagHead() opType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return opType(int(t.toNotIndent().headToStringTagHead()) + {{ .OpLen }})
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
{{- range $type := .OpTypes }}
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
|
{{- if $type.IsHeadToStringTagHead }}
|
||||||
case op{{ $type.Op }}:
|
case op{{ $type.Op }}:
|
||||||
return op{{ call $type.HeadToStringTagHead }}
|
return op{{ call $type.HeadToStringTagHead }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t opType) ptrHeadToHead() opType {
|
func (t opType) ptrHeadToHead() opType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return opType(int(t.toNotIndent().ptrHeadToHead()) + {{ .OpLen }})
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
{{- range $type := .OpTypes }}
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
|
{{- if $type.IsPtrHeadToHead }}
|
||||||
case op{{ $type.Op }}:
|
case op{{ $type.Op }}:
|
||||||
return op{{ call $type.PtrHeadToHead }}
|
return op{{ call $type.PtrHeadToHead }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t opType) fieldToEnd() opType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return opType(int(t.toNotIndent().fieldToEnd()) + {{ .OpLen }})
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
|
{{- if $type.IsFieldToEnd }}
|
||||||
|
case op{{ $type.Op }}:
|
||||||
|
return op{{ call $type.FieldToEnd }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t opType) fieldToOmitEmptyField() opType {
|
func (t opType) fieldToOmitEmptyField() opType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return opType(int(t.toNotIndent().fieldToOmitEmptyField()) + {{ .OpLen }})
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
{{- range $type := .OpTypes }}
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
|
{{- if $type.IsFieldToOmitEmptyField }}
|
||||||
case op{{ $type.Op }}:
|
case op{{ $type.Op }}:
|
||||||
return op{{ call $type.FieldToOmitEmptyField }}
|
return op{{ call $type.FieldToOmitEmptyField }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t opType) fieldToStringTagField() opType {
|
func (t opType) fieldToStringTagField() opType {
|
||||||
|
if int(t) >= {{ .OpLen }} {
|
||||||
|
return opType(int(t.toNotIndent().fieldToStringTagField()) + {{ .OpLen }})
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
{{- range $type := .OpTypes }}
|
{{- range $type := .OpNotIndentTypes }}
|
||||||
|
{{- if $type.IsFieldToStringTagField }}
|
||||||
case op{{ $type.Op }}:
|
case op{{ $type.Op }}:
|
||||||
return op{{ call $type.FieldToStringTagField }}
|
return op{{ call $type.FieldToStringTagField }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
|
@ -199,6 +323,7 @@ func (t opType) fieldToStringTagField() opType {
|
||||||
"MapEnd",
|
"MapEnd",
|
||||||
"StructFieldRecursive",
|
"StructFieldRecursive",
|
||||||
"StructField",
|
"StructField",
|
||||||
|
"StructEnd",
|
||||||
}
|
}
|
||||||
primitiveTypes := []string{
|
primitiveTypes := []string{
|
||||||
"int", "int8", "int16", "int32", "int64",
|
"int", "int8", "int16", "int32", "int64",
|
||||||
|
@ -238,8 +363,7 @@ func (t opType) fieldToStringTagField() opType {
|
||||||
createOpType("MapValue", "MapValue"),
|
createOpType("MapValue", "MapValue"),
|
||||||
createOpType("MapEnd", "Op"),
|
createOpType("MapEnd", "Op"),
|
||||||
createOpType("StructFieldRecursiveEnd", "Op"),
|
createOpType("StructFieldRecursiveEnd", "Op"),
|
||||||
createOpType("StructEnd", "StructField"),
|
createOpType("StructAnonymousEnd", "StructEnd"),
|
||||||
createOpType("StructAnonymousEnd", "StructField"),
|
|
||||||
}
|
}
|
||||||
for _, typ := range primitiveTypesUpper {
|
for _, typ := range primitiveTypesUpper {
|
||||||
typ := typ
|
typ := typ
|
||||||
|
@ -348,6 +472,7 @@ func (t opType) fieldToStringTagField() opType {
|
||||||
typ,
|
typ,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
FieldToEnd: func() string { return op },
|
||||||
FieldToOmitEmptyField: func() string { return op },
|
FieldToOmitEmptyField: func() string { return op },
|
||||||
FieldToStringTagField: func() string { return op },
|
FieldToStringTagField: func() string { return op },
|
||||||
})
|
})
|
||||||
|
@ -394,6 +519,18 @@ func (t opType) fieldToStringTagField() opType {
|
||||||
HeadToOmitEmptyHead: func() string { return op },
|
HeadToOmitEmptyHead: func() string { return op },
|
||||||
HeadToStringTagHead: func() string { return op },
|
HeadToStringTagHead: func() string { return op },
|
||||||
PtrHeadToHead: func() string { return op },
|
PtrHeadToHead: func() string { return op },
|
||||||
|
FieldToEnd: func() string {
|
||||||
|
switch typ {
|
||||||
|
case "", "Array", "Map", "MapLoad", "Slice", "Struct", "Recursive":
|
||||||
|
return op
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"Struct%sEnd%s%s",
|
||||||
|
escapedOrNot,
|
||||||
|
opt,
|
||||||
|
typ,
|
||||||
|
)
|
||||||
|
},
|
||||||
FieldToOmitEmptyField: func() string {
|
FieldToOmitEmptyField: func() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"Struct%sFieldOmitEmpty%s",
|
"Struct%sFieldOmitEmpty%s",
|
||||||
|
@ -412,6 +549,51 @@ func (t opType) fieldToStringTagField() opType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, escapedOrNot := range []string{"", "Escaped"} {
|
||||||
|
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
|
||||||
|
for _, typ := range append(primitiveTypesUpper, "") {
|
||||||
|
escapedOrNot := escapedOrNot
|
||||||
|
opt := opt
|
||||||
|
typ := typ
|
||||||
|
|
||||||
|
op := fmt.Sprintf(
|
||||||
|
"Struct%sEnd%s%s",
|
||||||
|
escapedOrNot,
|
||||||
|
opt,
|
||||||
|
typ,
|
||||||
|
)
|
||||||
|
opTypes = append(opTypes, opType{
|
||||||
|
Op: op,
|
||||||
|
Code: "StructEnd",
|
||||||
|
Indent: func() string { return fmt.Sprintf("%sIndent", op) },
|
||||||
|
Escaped: func() string {
|
||||||
|
switch typ {
|
||||||
|
case "String", "StringPtr", "StringNPtr":
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"StructEscapedEnd%sEscaped%s",
|
||||||
|
opt,
|
||||||
|
typ,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"StructEscapedEnd%s%s",
|
||||||
|
opt,
|
||||||
|
typ,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
HeadToPtrHead: func() string { return op },
|
||||||
|
HeadToNPtrHead: func() string { return op },
|
||||||
|
HeadToAnonymousHead: func() string { return op },
|
||||||
|
HeadToOmitEmptyHead: func() string { return op },
|
||||||
|
HeadToStringTagHead: func() string { return op },
|
||||||
|
PtrHeadToHead: func() string { return op },
|
||||||
|
FieldToEnd: func() string { return op },
|
||||||
|
FieldToOmitEmptyField: func() string { return op },
|
||||||
|
FieldToStringTagField: func() string { return op },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
indentOpTypes := []opType{}
|
indentOpTypes := []opType{}
|
||||||
for _, typ := range opTypes {
|
for _, typ := range opTypes {
|
||||||
typ := typ
|
typ := typ
|
||||||
|
@ -444,15 +626,24 @@ func (t opType) fieldToStringTagField() opType {
|
||||||
FieldToStringTagField: func() string {
|
FieldToStringTagField: func() string {
|
||||||
return fmt.Sprintf("%sIndent", typ.FieldToStringTagField())
|
return fmt.Sprintf("%sIndent", typ.FieldToStringTagField())
|
||||||
},
|
},
|
||||||
|
FieldToEnd: func() string {
|
||||||
|
return fmt.Sprintf("%sIndent", typ.FieldToEnd())
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
if err := tmpl.Execute(&b, struct {
|
if err := tmpl.Execute(&b, struct {
|
||||||
CodeTypes []string
|
CodeTypes []string
|
||||||
OpTypes []opType
|
OpTypes []opType
|
||||||
|
OpNotIndentTypes []opType
|
||||||
|
OpLen int
|
||||||
|
OpIndentLen int
|
||||||
}{
|
}{
|
||||||
CodeTypes: codeTypes,
|
CodeTypes: codeTypes,
|
||||||
OpTypes: append(opTypes, indentOpTypes...),
|
OpTypes: append(opTypes, indentOpTypes...),
|
||||||
|
OpNotIndentTypes: opTypes,
|
||||||
|
OpLen: len(opTypes),
|
||||||
|
OpIndentLen: len(indentOpTypes),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
11
encode.go
11
encode.go
|
@ -312,6 +312,17 @@ func encodeIndentComma(b []byte) []byte {
|
||||||
return append(b, ',', '\n')
|
return append(b, ',', '\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendStructEnd(b []byte) []byte {
|
||||||
|
return append(b, '}', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) appendStructEndIndent(b []byte, indent int) []byte {
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = append(b, e.prefix...)
|
||||||
|
b = append(b, bytes.Repeat(e.indentStr, indent)...)
|
||||||
|
return append(b, '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
func encodeByteSlice(b []byte, src []byte) []byte {
|
func encodeByteSlice(b []byte, src []byte) []byte {
|
||||||
encodedLen := base64.StdEncoding.EncodedLen(len(src))
|
encodedLen := base64.StdEncoding.EncodedLen(len(src))
|
||||||
b = append(b, '"')
|
b = append(b, '"')
|
||||||
|
|
|
@ -3,6 +3,7 @@ package json
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,13 +28,64 @@ func (e *Encoder) compileHead(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
if typ.Kind() == reflect.Map {
|
if typ.Kind() == reflect.Map {
|
||||||
return e.compileMap(ctx.withType(typ), isPtr)
|
return e.compileMap(ctx.withType(typ), isPtr)
|
||||||
} else if typ.Kind() == reflect.Struct {
|
} else if typ.Kind() == reflect.Struct {
|
||||||
return e.compileStruct(ctx.withType(typ), isPtr)
|
code, err := e.compileStruct(ctx.withType(typ), isPtr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e.optimizeStructEnd(code)
|
||||||
|
return code, nil
|
||||||
} else if isPtr && typ.Implements(marshalTextType) {
|
} else if isPtr && typ.Implements(marshalTextType) {
|
||||||
typ = orgType
|
typ = orgType
|
||||||
} else if isPtr && typ.Implements(marshalJSONType) {
|
} else if isPtr && typ.Implements(marshalJSONType) {
|
||||||
typ = orgType
|
typ = orgType
|
||||||
}
|
}
|
||||||
return e.compile(ctx.withType(typ))
|
code, err := e.compile(ctx.withType(typ))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e.optimizeStructEnd(code)
|
||||||
|
return code, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) optimizeStructEnd(c *opcode) {
|
||||||
|
for code := c; code.op != opEnd; {
|
||||||
|
if code.op == opStructFieldRecursive {
|
||||||
|
// ignore if exists recursive operation
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch code.op.codeType() {
|
||||||
|
case codeArrayElem, codeSliceElem, codeMapKey:
|
||||||
|
code = code.end
|
||||||
|
default:
|
||||||
|
code = code.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for code := c; code.op != opEnd; {
|
||||||
|
switch code.op.codeType() {
|
||||||
|
case codeArrayElem, codeSliceElem, codeMapKey:
|
||||||
|
code = code.end
|
||||||
|
case codeStructEnd:
|
||||||
|
switch code.op {
|
||||||
|
case opStructEnd:
|
||||||
|
prev := code.prevField
|
||||||
|
if strings.Contains(prev.op.String(), "Head") {
|
||||||
|
// not exists field
|
||||||
|
code = code.next
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if prev.op != prev.op.fieldToEnd() {
|
||||||
|
prev.op = prev.op.fieldToEnd()
|
||||||
|
prev.next = code.next
|
||||||
|
}
|
||||||
|
code = code.next
|
||||||
|
default:
|
||||||
|
code = code.next
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
code = code.next
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) implementsMarshaler(typ *rtype) bool {
|
func (e *Encoder) implementsMarshaler(typ *rtype) bool {
|
||||||
|
|
|
@ -324,6 +324,9 @@ func (c *opcode) dump() string {
|
||||||
case codeStructField:
|
case codeStructField:
|
||||||
codes = append(codes, c.dumpField(code))
|
codes = append(codes, c.dumpField(code))
|
||||||
code = code.next
|
code = code.next
|
||||||
|
case codeStructEnd:
|
||||||
|
codes = append(codes, c.dumpField(code))
|
||||||
|
code = code.next
|
||||||
default:
|
default:
|
||||||
codes = append(codes, fmt.Sprintf(
|
codes = append(codes, fmt.Sprintf(
|
||||||
"[%d]%s%s ([idx:%d])",
|
"[%d]%s%s ([idx:%d])",
|
||||||
|
|
119603
encode_optype.go
119603
encode_optype.go
File diff suppressed because it is too large
Load Diff
2211
encode_vm.go
2211
encode_vm.go
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue