forked from mirror/go-json
Refactor compileStruct
This commit is contained in:
parent
901128a986
commit
45f59f6fff
|
@ -746,33 +746,80 @@ func (e *Encoder) optimizeStructField(op opType, isOmitEmpty, withIndent bool) o
|
||||||
return opStructField
|
return opStructField
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileStruct(typ *rtype, root, withIndent bool) (*opcode, error) {
|
func (e *Encoder) recursiveCode(typ *rtype, code *compiledCode) *opcode {
|
||||||
|
return (*opcode)(unsafe.Pointer(&recursiveCode{
|
||||||
|
opcodeHeader: &opcodeHeader{
|
||||||
|
op: opStructFieldRecursive,
|
||||||
|
typ: typ,
|
||||||
|
indent: e.indent,
|
||||||
|
next: newEndOp(e.indent),
|
||||||
|
},
|
||||||
|
jmp: code,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) compiledCode(typ *rtype, withIndent bool) *opcode {
|
||||||
typeptr := uintptr(unsafe.Pointer(typ))
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
if withIndent {
|
if withIndent {
|
||||||
if compiled, exists := e.structTypeToCompiledIndentCode[typeptr]; exists {
|
if compiledCode, exists := e.structTypeToCompiledIndentCode[typeptr]; exists {
|
||||||
return (*opcode)(unsafe.Pointer(&recursiveCode{
|
return e.recursiveCode(typ, compiledCode)
|
||||||
opcodeHeader: &opcodeHeader{
|
|
||||||
op: opStructFieldRecursive,
|
|
||||||
typ: typ,
|
|
||||||
indent: e.indent,
|
|
||||||
next: newEndOp(e.indent),
|
|
||||||
},
|
|
||||||
jmp: compiled,
|
|
||||||
})), nil
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if compiled, exists := e.structTypeToCompiledCode[typeptr]; exists {
|
if compiledCode, exists := e.structTypeToCompiledCode[typeptr]; exists {
|
||||||
return (*opcode)(unsafe.Pointer(&recursiveCode{
|
return e.recursiveCode(typ, compiledCode)
|
||||||
opcodeHeader: &opcodeHeader{
|
|
||||||
op: opStructFieldRecursive,
|
|
||||||
typ: typ,
|
|
||||||
indent: e.indent,
|
|
||||||
next: newEndOp(e.indent),
|
|
||||||
},
|
|
||||||
jmp: compiled,
|
|
||||||
})), nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) keyNameAndOmitEmptyFromField(field reflect.StructField) (string, bool) {
|
||||||
|
keyName := field.Name
|
||||||
|
tag := e.getTag(field)
|
||||||
|
opts := strings.Split(tag, ",")
|
||||||
|
if len(opts) > 0 {
|
||||||
|
if opts[0] != "" {
|
||||||
|
keyName = opts[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isOmitEmpty := false
|
||||||
|
if len(opts) > 1 {
|
||||||
|
isOmitEmpty = opts[1] == "omitempty"
|
||||||
|
}
|
||||||
|
return keyName, isOmitEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) structHeader(fieldCode *structFieldCode, valueCode *opcode, isOmitEmpty, withIndent bool) *opcode {
|
||||||
|
fieldCode.indent--
|
||||||
|
op := e.optimizeStructHeader(valueCode.op, isOmitEmpty, withIndent)
|
||||||
|
fieldCode.op = op
|
||||||
|
switch op {
|
||||||
|
case opStructFieldHead,
|
||||||
|
opStructFieldHeadOmitEmpty,
|
||||||
|
opStructFieldHeadIndent,
|
||||||
|
opStructFieldHeadOmitEmptyIndent:
|
||||||
|
return valueCode.beforeLastCode()
|
||||||
|
}
|
||||||
|
return (*opcode)(unsafe.Pointer(fieldCode))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) structField(fieldCode *structFieldCode, valueCode *opcode, isOmitEmpty, withIndent bool) *opcode {
|
||||||
|
code := (*opcode)(unsafe.Pointer(fieldCode))
|
||||||
|
op := e.optimizeStructField(valueCode.op, isOmitEmpty, withIndent)
|
||||||
|
fieldCode.op = op
|
||||||
|
switch op {
|
||||||
|
case opStructField,
|
||||||
|
opStructFieldOmitEmpty,
|
||||||
|
opStructFieldIndent,
|
||||||
|
opStructFieldOmitEmptyIndent:
|
||||||
|
return valueCode.beforeLastCode()
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
func (e *Encoder) compileStruct(typ *rtype, root, withIndent bool) (*opcode, error) {
|
||||||
|
if code := e.compiledCode(typ, withIndent); code != nil {
|
||||||
|
return code, nil
|
||||||
|
}
|
||||||
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
compiled := &compiledCode{}
|
compiled := &compiledCode{}
|
||||||
if withIndent {
|
if withIndent {
|
||||||
e.structTypeToCompiledIndentCode[typeptr] = compiled
|
e.structTypeToCompiledIndentCode[typeptr] = compiled
|
||||||
|
@ -795,18 +842,7 @@ func (e *Encoder) compileStruct(typ *rtype, root, withIndent bool) (*opcode, err
|
||||||
if e.isIgnoredStructField(field) {
|
if e.isIgnoredStructField(field) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
keyName := field.Name
|
keyName, isOmitEmpty := e.keyNameAndOmitEmptyFromField(field)
|
||||||
tag := e.getTag(field)
|
|
||||||
opts := strings.Split(tag, ",")
|
|
||||||
if len(opts) > 0 {
|
|
||||||
if opts[0] != "" {
|
|
||||||
keyName = opts[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isOmitEmpty := false
|
|
||||||
if len(opts) > 1 {
|
|
||||||
isOmitEmpty = opts[1] == "omitempty"
|
|
||||||
}
|
|
||||||
fieldType := type2rtype(field.Type)
|
fieldType := type2rtype(field.Type)
|
||||||
valueCode, err := e.compile(fieldType, false, withIndent)
|
valueCode, err := e.compile(fieldType, false, withIndent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -823,40 +859,22 @@ func (e *Encoder) compileStruct(typ *rtype, root, withIndent bool) (*opcode, err
|
||||||
offset: field.Offset,
|
offset: field.Offset,
|
||||||
}
|
}
|
||||||
if fieldIdx == 0 {
|
if fieldIdx == 0 {
|
||||||
fieldCode.indent--
|
code = e.structHeader(fieldCode, valueCode, isOmitEmpty, withIndent)
|
||||||
head = fieldCode
|
head = fieldCode
|
||||||
code = (*opcode)(unsafe.Pointer(fieldCode))
|
|
||||||
prevField = fieldCode
|
prevField = fieldCode
|
||||||
op := e.optimizeStructHeader(valueCode.op, isOmitEmpty, withIndent)
|
|
||||||
fieldCode.op = op
|
|
||||||
switch op {
|
|
||||||
case opStructFieldHead,
|
|
||||||
opStructFieldHeadOmitEmpty,
|
|
||||||
opStructFieldHeadIndent,
|
|
||||||
opStructFieldHeadOmitEmptyIndent:
|
|
||||||
code = valueCode.beforeLastCode()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
code.next = (*opcode)(unsafe.Pointer(fieldCode))
|
fcode := (*opcode)(unsafe.Pointer(fieldCode))
|
||||||
prevField.nextField = (*opcode)(unsafe.Pointer(fieldCode))
|
code.next = fcode
|
||||||
|
code = e.structField(fieldCode, valueCode, isOmitEmpty, withIndent)
|
||||||
|
prevField.nextField = fcode
|
||||||
prevField = fieldCode
|
prevField = fieldCode
|
||||||
code = (*opcode)(unsafe.Pointer(fieldCode))
|
|
||||||
op := e.optimizeStructField(valueCode.op, isOmitEmpty, withIndent)
|
|
||||||
fieldCode.op = op
|
|
||||||
switch op {
|
|
||||||
case opStructField,
|
|
||||||
opStructFieldOmitEmpty,
|
|
||||||
opStructFieldIndent,
|
|
||||||
opStructFieldOmitEmptyIndent:
|
|
||||||
code = valueCode.beforeLastCode()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fieldIdx++
|
fieldIdx++
|
||||||
}
|
}
|
||||||
e.indent--
|
e.indent--
|
||||||
|
|
||||||
structEndCode := newOpCode(opStructEnd, nil, e.indent, nil)
|
structEndCode := newOpCode(opStructEnd, nil, e.indent, nil)
|
||||||
|
structEndCode.next = newEndOp(e.indent)
|
||||||
if withIndent {
|
if withIndent {
|
||||||
structEndCode.op = opStructEndIndent
|
structEndCode.op = opStructEndIndent
|
||||||
}
|
}
|
||||||
|
@ -882,7 +900,6 @@ func (e *Encoder) compileStruct(typ *rtype, root, withIndent bool) (*opcode, err
|
||||||
}
|
}
|
||||||
head.end = structEndCode
|
head.end = structEndCode
|
||||||
code.next = structEndCode
|
code.next = structEndCode
|
||||||
structEndCode.next = newEndOp(e.indent)
|
|
||||||
ret := (*opcode)(unsafe.Pointer(head))
|
ret := (*opcode)(unsafe.Pointer(head))
|
||||||
compiled.code = ret
|
compiled.code = ret
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|
Loading…
Reference in New Issue