Refactor indent parameter

This commit is contained in:
Masaaki Goshima 2020-08-29 15:35:03 +09:00
parent 7dcadbd6ce
commit e508ad41ba
5 changed files with 107 additions and 67 deletions

View File

@ -19,7 +19,6 @@ type Encoder struct {
enabledHTMLEscape bool enabledHTMLEscape bool
prefix []byte prefix []byte
indentStr []byte indentStr []byte
indent int
structTypeToCompiledCode map[uintptr]*compiledCode structTypeToCompiledCode map[uintptr]*compiledCode
structTypeToCompiledIndentCode map[uintptr]*compiledCode structTypeToCompiledIndentCode map[uintptr]*compiledCode
} }
@ -123,7 +122,6 @@ func (e *Encoder) release() {
func (e *Encoder) reset() { func (e *Encoder) reset() {
e.buf = e.buf[:0] e.buf = e.buf[:0]
e.indent = 0
e.enabledHTMLEscape = true e.enabledHTMLEscape = true
e.enabledIndent = false e.enabledIndent = false
} }

View File

@ -10,13 +10,13 @@ func (e *Encoder) compileHead(ctx *encodeCompileContext) (*opcode, error) {
typ := ctx.typ typ := ctx.typ
switch { switch {
case typ.Implements(marshalJSONType): case typ.Implements(marshalJSONType):
return newOpCode(opMarshalJSON, typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opMarshalJSON), nil
case rtype_ptrTo(typ).Implements(marshalJSONType): case rtype_ptrTo(typ).Implements(marshalJSONType):
return newOpCode(opMarshalJSON, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil return newOpCode(ctx.withType(rtype_ptrTo(typ)), opMarshalJSON), nil
case typ.Implements(marshalTextType): case typ.Implements(marshalTextType):
return newOpCode(opMarshalText, typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opMarshalText), nil
case rtype_ptrTo(typ).Implements(marshalTextType): case rtype_ptrTo(typ).Implements(marshalTextType):
return newOpCode(opMarshalText, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil return newOpCode(ctx.withType(rtype_ptrTo(typ)), opMarshalText), nil
} }
isPtr := false isPtr := false
if typ.Kind() == reflect.Ptr { if typ.Kind() == reflect.Ptr {
@ -49,13 +49,13 @@ func (e *Encoder) compile(ctx *encodeCompileContext) (*opcode, error) {
typ := ctx.typ typ := ctx.typ
switch { switch {
case typ.Implements(marshalJSONType): case typ.Implements(marshalJSONType):
return newOpCode(opMarshalJSON, typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opMarshalJSON), nil
case rtype_ptrTo(typ).Implements(marshalJSONType): case rtype_ptrTo(typ).Implements(marshalJSONType):
return newOpCode(opMarshalJSON, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil return newOpCode(ctx.withType(rtype_ptrTo(typ)), opMarshalJSON), nil
case typ.Implements(marshalTextType): case typ.Implements(marshalTextType):
return newOpCode(opMarshalText, typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opMarshalText), nil
case rtype_ptrTo(typ).Implements(marshalTextType): case rtype_ptrTo(typ).Implements(marshalTextType):
return newOpCode(opMarshalText, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil return newOpCode(ctx.withType(rtype_ptrTo(typ)), opMarshalText), nil
} }
switch typ.Kind() { switch typ.Kind() {
case reflect.Ptr: case reflect.Ptr:
@ -112,13 +112,13 @@ func (e *Encoder) compileKey(ctx *encodeCompileContext) (*opcode, error) {
typ := ctx.typ typ := ctx.typ
switch { switch {
case typ.Implements(marshalJSONType): case typ.Implements(marshalJSONType):
return newOpCode(opMarshalJSON, typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opMarshalJSON), nil
case rtype_ptrTo(typ).Implements(marshalJSONType): case rtype_ptrTo(typ).Implements(marshalJSONType):
return newOpCode(opMarshalJSON, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil return newOpCode(ctx.withType(rtype_ptrTo(typ)), opMarshalJSON), nil
case typ.Implements(marshalTextType): case typ.Implements(marshalTextType):
return newOpCode(opMarshalText, typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opMarshalText), nil
case rtype_ptrTo(typ).Implements(marshalTextType): case rtype_ptrTo(typ).Implements(marshalTextType):
return newOpCode(opMarshalText, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil return newOpCode(ctx.withType(rtype_ptrTo(typ)), opMarshalText), nil
} }
switch typ.Kind() { switch typ.Kind() {
case reflect.Ptr: case reflect.Ptr:
@ -132,13 +132,12 @@ func (e *Encoder) compileKey(ctx *encodeCompileContext) (*opcode, error) {
} }
func (e *Encoder) optimizeStructFieldPtrHead(ctx *encodeCompileContext, code *opcode) *opcode { func (e *Encoder) optimizeStructFieldPtrHead(ctx *encodeCompileContext, code *opcode) *opcode {
typ := ctx.typ
ptrHeadOp := code.op.headToPtrHead() ptrHeadOp := code.op.headToPtrHead()
if code.op != ptrHeadOp { if code.op != ptrHeadOp {
code.op = ptrHeadOp code.op = ptrHeadOp
return code return code
} }
return newOpCode(opPtr, typ, e.indent, code) return newOpCodeWithNext(ctx, opPtr, code)
} }
func (e *Encoder) compilePtr(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compilePtr(ctx *encodeCompileContext) (*opcode, error) {
@ -150,63 +149,63 @@ func (e *Encoder) compilePtr(ctx *encodeCompileContext) (*opcode, error) {
} }
func (e *Encoder) compileInt(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileInt(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opInt, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opInt), nil
} }
func (e *Encoder) compileInt8(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileInt8(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opInt8, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opInt8), nil
} }
func (e *Encoder) compileInt16(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileInt16(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opInt16, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opInt16), nil
} }
func (e *Encoder) compileInt32(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileInt32(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opInt32, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opInt32), nil
} }
func (e *Encoder) compileInt64(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileInt64(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opInt64, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opInt64), nil
} }
func (e *Encoder) compileUint(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileUint(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opUint, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opUint), nil
} }
func (e *Encoder) compileUint8(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileUint8(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opUint8, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opUint8), nil
} }
func (e *Encoder) compileUint16(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileUint16(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opUint16, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opUint16), nil
} }
func (e *Encoder) compileUint32(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileUint32(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opUint32, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opUint32), nil
} }
func (e *Encoder) compileUint64(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileUint64(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opUint64, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opUint64), nil
} }
func (e *Encoder) compileFloat32(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileFloat32(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opFloat32, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opFloat32), nil
} }
func (e *Encoder) compileFloat64(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileFloat64(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opFloat64, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opFloat64), nil
} }
func (e *Encoder) compileString(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileString(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opString, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opString), nil
} }
func (e *Encoder) compileBool(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileBool(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opBool, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opBool), nil
} }
func (e *Encoder) compileBytes(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileBytes(ctx *encodeCompileContext) (*opcode, error) {
return newOpCode(opBytes, ctx.typ, e.indent, newEndOp(e.indent)), nil return newOpCode(ctx, opBytes), nil
} }
func (e *Encoder) compileInterface(ctx *encodeCompileContext) (*opcode, error) { func (e *Encoder) compileInterface(ctx *encodeCompileContext) (*opcode, error) {
@ -214,8 +213,8 @@ func (e *Encoder) compileInterface(ctx *encodeCompileContext) (*opcode, error) {
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opInterface, op: opInterface,
typ: ctx.typ, typ: ctx.typ,
indent: e.indent, indent: ctx.indent,
next: newEndOp(e.indent), next: newEndOp(ctx),
}, },
root: ctx.root, root: ctx.root,
})), nil })), nil
@ -226,10 +225,7 @@ func (e *Encoder) compileSlice(ctx *encodeCompileContext) (*opcode, error) {
elem := ctx.typ.Elem() elem := ctx.typ.Elem()
size := elem.Size() size := elem.Size()
e.indent++ code, err := e.compile(ctx.withType(ctx.typ.Elem()).incIndent())
code, err := e.compile(ctx.withType(ctx.typ.Elem()))
e.indent--
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -238,15 +234,15 @@ func (e *Encoder) compileSlice(ctx *encodeCompileContext) (*opcode, error) {
// ^ | // ^ |
// |________| // |________|
header := newSliceHeaderCode(e.indent) header := newSliceHeaderCode(ctx.indent)
elemCode := &sliceElemCode{ elemCode := &sliceElemCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opSliceElem, op: opSliceElem,
indent: e.indent, indent: ctx.indent,
}, },
size: size, size: size,
} }
end := newOpCode(opSliceEnd, nil, e.indent, newEndOp(e.indent)) end := newOpCode(ctx, opSliceEnd)
if ctx.withIndent { if ctx.withIndent {
if ctx.root { if ctx.root {
header.op = opRootSliceHeadIndent header.op = opRootSliceHeadIndent
@ -274,10 +270,7 @@ func (e *Encoder) compileArray(ctx *encodeCompileContext) (*opcode, error) {
alen := typ.Len() alen := typ.Len()
size := elem.Size() size := elem.Size()
e.indent++ code, err := e.compile(ctx.withType(elem).incIndent())
code, err := e.compile(ctx.withType(elem))
e.indent--
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -285,7 +278,7 @@ func (e *Encoder) compileArray(ctx *encodeCompileContext) (*opcode, error) {
// ^ | // ^ |
// |________| // |________|
header := newArrayHeaderCode(e.indent, alen) header := newArrayHeaderCode(ctx.indent, alen)
elemCode := &arrayElemCode{ elemCode := &arrayElemCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opArrayElem, op: opArrayElem,
@ -293,7 +286,7 @@ func (e *Encoder) compileArray(ctx *encodeCompileContext) (*opcode, error) {
len: uintptr(alen), len: uintptr(alen),
size: size, size: size,
} }
end := newOpCode(opArrayEnd, nil, e.indent, newEndOp(e.indent)) end := newOpCode(ctx, opArrayEnd)
if ctx.withIndent { if ctx.withIndent {
header.op = opArrayHeadIndent header.op = opArrayHeadIndent
@ -330,7 +323,7 @@ func (e *Encoder) compileMap(ctx *encodeCompileContext, withLoad bool) (*opcode,
// header => code => value => code => key => code => value => code => end // header => code => value => code => key => code => value => code => end
// ^ | // ^ |
// |_______________________| // |_______________________|
e.indent++ ctx = ctx.incIndent()
typ := ctx.typ typ := ctx.typ
keyType := ctx.typ.Key() keyType := ctx.typ.Key()
keyCode, err := e.compileKey(ctx.withType(keyType)) keyCode, err := e.compileKey(ctx.withType(keyType))
@ -343,15 +336,15 @@ func (e *Encoder) compileMap(ctx *encodeCompileContext, withLoad bool) (*opcode,
return nil, err return nil, err
} }
key := newMapKeyCode(e.indent) key := newMapKeyCode(ctx.indent)
value := newMapValueCode(e.indent) value := newMapValueCode(ctx.indent)
e.indent-- ctx = ctx.decIndent()
header := newMapHeaderCode(typ, withLoad, e.indent) header := newMapHeaderCode(typ, withLoad, ctx.indent)
header.key = key header.key = key
header.value = value header.value = value
end := newOpCode(opMapEnd, nil, e.indent, newEndOp(e.indent)) end := newOpCode(ctx, opMapEnd)
if ctx.withIndent { if ctx.withIndent {
if header.op == opMapHead { if header.op == opMapHead {
@ -533,8 +526,8 @@ func (e *Encoder) recursiveCode(ctx *encodeCompileContext, code *compiledCode) *
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opStructFieldRecursive, op: opStructFieldRecursive,
typ: ctx.typ, typ: ctx.typ,
indent: e.indent, indent: ctx.indent,
next: newEndOp(e.indent), next: newEndOp(ctx),
}, },
jmp: code, jmp: code,
})) }))
@ -793,7 +786,7 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
code *opcode code *opcode
prevField *structFieldCode prevField *structFieldCode
) )
e.indent++ ctx = ctx.incIndent()
tags := structTags{} tags := structTags{}
anonymousFields := map[string][]structFieldPair{} anonymousFields := map[string][]structFieldPair{}
for i := 0; i < fieldNum; i++ { for i := 0; i < fieldNum; i++ {
@ -839,7 +832,7 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
typ: valueCode.typ, typ: valueCode.typ,
next: valueCode, next: valueCode,
indent: e.indent, indent: ctx.indent,
}, },
anonymousKey: field.Anonymous, anonymousKey: field.Anonymous,
key: []byte(key), key: []byte(key),
@ -860,16 +853,16 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
} }
fieldIdx++ fieldIdx++
} }
e.indent-- ctx = ctx.decIndent()
structEndCode := (*opcode)(unsafe.Pointer(&structFieldCode{ structEndCode := (*opcode)(unsafe.Pointer(&structFieldCode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opStructEnd, op: opStructEnd,
typ: nil, typ: nil,
indent: e.indent, indent: ctx.indent,
}, },
})) }))
structEndCode.next = newEndOp(e.indent) structEndCode.next = newEndOp(ctx)
if ctx.withIndent { if ctx.withIndent {
structEndCode.op = opStructEndIndent structEndCode.op = opStructEndIndent
} }
@ -884,7 +877,7 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: opStructFieldHead, op: opStructFieldHead,
typ: typ, typ: typ,
indent: e.indent, indent: ctx.indent,
}, },
nextField: structEndCode, nextField: structEndCode,
} }

37
encode_context.go Normal file
View File

@ -0,0 +1,37 @@
package json
type encodeCompileContext struct {
typ *rtype
withIndent bool
root bool
opcodeIndex int
indent int
}
func (c *encodeCompileContext) context() *encodeCompileContext {
return &encodeCompileContext{
typ: c.typ,
withIndent: c.withIndent,
root: c.root,
opcodeIndex: c.opcodeIndex,
indent: c.indent,
}
}
func (c *encodeCompileContext) withType(typ *rtype) *encodeCompileContext {
ctx := c.context()
ctx.typ = typ
return ctx
}
func (c *encodeCompileContext) incIndent() *encodeCompileContext {
ctx := c.context()
ctx.indent++
return ctx
}
func (c *encodeCompileContext) decIndent() *encodeCompileContext {
ctx := c.context()
ctx.indent--
return ctx
}

View File

@ -34,19 +34,30 @@ type opcode struct {
*opcodeHeader *opcodeHeader
} }
func newOpCode(op opType, typ *rtype, indent int, next *opcode) *opcode { func newOpCode(ctx *encodeCompileContext, op opType) *opcode {
return &opcode{ return &opcode{
opcodeHeader: &opcodeHeader{ opcodeHeader: &opcodeHeader{
op: op, op: op,
typ: typ, typ: ctx.typ,
indent: indent, indent: ctx.indent,
next: newEndOp(ctx),
},
}
}
func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opcode {
return &opcode{
opcodeHeader: &opcodeHeader{
op: op,
typ: ctx.typ,
indent: ctx.indent,
next: next, next: next,
}, },
} }
} }
func newEndOp(indent int) *opcode { func newEndOp(ctx *encodeCompileContext) *opcode {
return newOpCode(opEnd, nil, indent, nil) return newOpCodeWithNext(ctx, opEnd, nil)
} }
func (c *opcode) beforeLastCode() *opcode { func (c *opcode) beforeLastCode() *opcode {
@ -547,7 +558,7 @@ func (c *recursiveCode) copy(codeMap map[uintptr]*opcode) *opcode {
func newRecursiveCode(recursive *recursiveCode) *opcode { func newRecursiveCode(recursive *recursiveCode) *opcode {
code := copyOpcode(recursive.jmp.code) code := copyOpcode(recursive.jmp.code)
head := (*structFieldCode)(unsafe.Pointer(code)) head := (*structFieldCode)(unsafe.Pointer(code))
head.end.next = newEndOp(0) head.end.next = newEndOp(&encodeCompileContext{})
code.ptr = recursive.ptr code.ptr = recursive.ptr
code.op = code.op.ptrHeadToHead() code.op = code.op.ptrHeadToHead()

View File

@ -109,13 +109,13 @@ func (e *Encoder) run(code *opcode) error {
if typ.Kind() == reflect.Ptr { if typ.Kind() == reflect.Ptr {
typ = typ.Elem() typ = typ.Elem()
} }
e.indent = ifaceCode.indent
var c *opcode var c *opcode
if typ.Kind() == reflect.Map { if typ.Kind() == reflect.Map {
code, err := e.compileMap(&encodeCompileContext{ code, err := e.compileMap(&encodeCompileContext{
typ: typ, typ: typ,
root: ifaceCode.root, root: ifaceCode.root,
withIndent: e.enabledIndent, withIndent: e.enabledIndent,
indent: ifaceCode.indent,
}, false) }, false)
if err != nil { if err != nil {
return err return err
@ -126,6 +126,7 @@ func (e *Encoder) run(code *opcode) error {
typ: typ, typ: typ,
root: ifaceCode.root, root: ifaceCode.root,
withIndent: e.enabledIndent, withIndent: e.enabledIndent,
indent: ifaceCode.indent,
}) })
if err != nil { if err != nil {
return err return err