work cover map and slice

This commit is contained in:
Masaaki Goshima 2021-11-25 13:10:01 +09:00
parent 6a00602e6a
commit f6d91525b2
No known key found for this signature in database
GPG Key ID: 6A53785055537153
7 changed files with 120 additions and 96 deletions

View File

@ -228,8 +228,8 @@ func (c *SliceCode) ToOpcode(ctx *compileContext) Opcodes {
size := c.typ.Elem().Size()
header := newSliceHeaderCode(ctx)
ctx.incIndex()
codes := c.value.ToOpcode(ctx)
elemCode := newSliceElemCode(ctx.withType(c.typ.Elem()).incIndent(), header, size)
codes := c.value.ToOpcode(ctx.incIndent())
elemCode := newSliceElemCode(ctx.withType(c.typ.Elem()), header, size)
ctx.incIndex()
end := newOpCode(ctx, OpSliceEnd)
ctx.incIndex()
@ -292,7 +292,6 @@ func (c *MapCode) ToOpcode(ctx *compileContext) Opcodes {
// header => code => value => code => key => code => value => code => end
// ^ |
// |_______________________|
ctx = ctx.incIndent()
header := newMapHeaderCode(ctx)
ctx.incIndex()
@ -300,13 +299,11 @@ func (c *MapCode) ToOpcode(ctx *compileContext) Opcodes {
value := newMapValueCode(ctx, header)
ctx.incIndex()
valueCodes := c.value.ToOpcode(ctx)
valueCodes := c.value.ToOpcode(ctx.incIndent())
key := newMapKeyCode(ctx, header)
ctx.incIndex()
ctx = ctx.decIndent()
end := newMapEndCode(ctx, header)
ctx.incIndex()
@ -340,14 +337,11 @@ func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes {
// header => code => structField => code => end
// ^ |
// |__________|
var recursive *Opcode
compiled := &CompiledCode{}
if c.isRecursive {
recursive = newRecursiveCode(ctx, compiled)
recursive := newRecursiveCode(ctx, &CompiledCode{})
recursive.Type = c.typ
ctx.incIndex()
}
if len(c.recursiveCodes) > 0 {
c.linkRecursiveCode(compiled, c.recursiveCodes)
*ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive)
return Opcodes{recursive}
}
codes := Opcodes{}
@ -389,12 +383,27 @@ func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes {
}
codes = append(codes, fieldCodes...)
}
ctx = ctx.decIndent()
if c.isRecursive {
c.recursiveCodes = codes
c.linkRecursiveCode(compiled, c.recursiveCodes)
return Opcodes{recursive}
if len(codes) == 0 {
end := &Opcode{
Op: OpStructEnd,
Idx: opcodeOffset(ctx.ptrIndex),
DisplayIdx: ctx.opcodeIndex,
Indent: ctx.indent,
}
head := &Opcode{
Op: OpStructHead,
Idx: opcodeOffset(ctx.ptrIndex),
NextField: end,
Type: c.typ,
DisplayIdx: ctx.opcodeIndex,
Indent: ctx.indent,
}
codes = append(codes, head, end)
end.PrevField = head
ctx.incIndex()
}
ctx = ctx.decIndent()
ctx.structTypeToCodes[uintptr(unsafe.Pointer(c.typ))] = codes
return codes
}
@ -402,14 +411,11 @@ func (c *StructCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
// header => code => structField => code => end
// ^ |
// |__________|
var recursive *Opcode
compiled := &CompiledCode{}
if c.isRecursive {
recursive = newRecursiveCode(ctx, compiled)
recursive := newRecursiveCode(ctx, &CompiledCode{})
recursive.Type = c.typ
ctx.incIndex()
}
if len(c.recursiveCodes) > 0 {
c.linkRecursiveCode(compiled, c.recursiveCodes)
*ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive)
return Opcodes{recursive}
}
codes := Opcodes{}
@ -440,36 +446,35 @@ func (c *StructCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
prevField = fieldCodes.First()
codes = append(codes, fieldCodes...)
}
if c.isRecursive {
c.recursiveCodes = codes
c.linkRecursiveCode(compiled, c.recursiveCodes)
return Opcodes{recursive}
}
return codes
}
func (c *StructCode) linkRecursiveCode(compiled *CompiledCode, codes Opcodes) {
compiled.Code = copyOpcode(codes.First())
code := compiled.Code
code.End.Next = newEndOp(&compileContext{})
code.Op = code.Op.PtrHeadToHead()
func linkRecursiveCode2(ctx *compileContext) {
for _, recursive := range *ctx.recursiveCodes {
typeptr := uintptr(unsafe.Pointer(recursive.Type))
codes := ctx.structTypeToCodes[typeptr]
compiled := recursive.Jmp
compiled.Code = copyOpcode(codes.First())
code := compiled.Code
code.End.Next = newEndOp(&compileContext{})
code.Op = code.Op.PtrHeadToHead()
beforeLastCode := code.End
lastCode := beforeLastCode.Next
beforeLastCode := code.End
lastCode := beforeLastCode.Next
lastCode.Idx = beforeLastCode.Idx + uintptrSize
lastCode.ElemIdx = lastCode.Idx + uintptrSize
lastCode.Length = lastCode.Idx + 2*uintptrSize
lastCode.Idx = beforeLastCode.Idx + uintptrSize
lastCode.ElemIdx = lastCode.Idx + uintptrSize
lastCode.Length = lastCode.Idx + 2*uintptrSize
code.End.Next.Op = OpRecursiveEnd
// extend length to alloc slot for elemIdx + length
totalLength := uintptr((codes.Last().MaxIdx() / uintptrSize) + 3)
nextTotalLength := uintptr(code.TotalLength() + 3)
// extend length to alloc slot for elemIdx + length
totalLength := uintptr(recursive.TotalLength()) + 3
nextTotalLength := uintptr(codes.First().TotalLength()) + 3
code.End.Next.Op = OpRecursiveEnd
compiled.CurLen = totalLength
compiled.NextLen = nextTotalLength
compiled.Linked = true
compiled.CurLen = totalLength
compiled.NextLen = nextTotalLength
compiled.Linked = true
}
}
func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) {
@ -567,9 +572,9 @@ func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField
ctx.incIndex()
var codes Opcodes
if c.isAnonymous {
codes = c.value.(AnonymousCode).ToAnonymousOpcode(ctx)
codes = c.value.(AnonymousCode).ToAnonymousOpcode(ctx.withType(c.typ))
} else {
codes = c.value.ToOpcode(ctx)
codes = c.value.ToOpcode(ctx.withType(c.typ))
}
if isFirstField {
op := optimizeStructHeader(codes.First(), c.tag)
@ -673,9 +678,9 @@ func (c *StructFieldCode) ToAnonymousOpcode(ctx *compileContext, isFirstField, i
ctx.incIndex()
var codes Opcodes
if c.isAnonymous {
codes = c.value.(AnonymousCode).ToAnonymousOpcode(ctx)
codes = c.value.(AnonymousCode).ToAnonymousOpcode(ctx.withType(c.typ))
} else {
codes = c.value.ToOpcode(ctx)
codes = c.value.ToOpcode(ctx.withType(c.typ))
}
if isFirstField {
op := optimizeStructHeader(codes.First(), c.tag)
@ -746,7 +751,7 @@ func (c *MarshalJSONCode) Type() CodeType2 {
}
func (c *MarshalJSONCode) ToOpcode(ctx *compileContext) Opcodes {
code := newOpCode(ctx, OpMarshalJSON)
code := newOpCode(ctx.withType(c.typ), OpMarshalJSON)
typ := c.typ
if isPtrMarshalJSONType(typ) {
code.Flags |= AddrForMarshalerFlags
@ -772,7 +777,7 @@ func (c *MarshalTextCode) Type() CodeType2 {
}
func (c *MarshalTextCode) ToOpcode(ctx *compileContext) Opcodes {
code := newOpCode(ctx, OpMarshalText)
code := newOpCode(ctx.withType(c.typ), OpMarshalText)
typ := c.typ
if !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType) {
code.Flags |= AddrForMarshalerFlags
@ -797,14 +802,14 @@ func (c *PtrCode) Type() CodeType2 {
}
func (c *PtrCode) ToOpcode(ctx *compileContext) Opcodes {
codes := c.value.ToOpcode(ctx)
codes := c.value.ToOpcode(ctx.withType(c.typ.Elem()))
codes.First().Op = convertPtrOp(codes.First())
codes.First().PtrNum = c.ptrNum
return codes
}
func (c *PtrCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
codes := c.value.(AnonymousCode).ToAnonymousOpcode(ctx)
codes := c.value.(AnonymousCode).ToAnonymousOpcode(ctx.withType(c.typ.Elem()))
codes.First().Op = convertPtrOp(codes.First())
codes.First().PtrNum = c.ptrNum
return codes
@ -954,17 +959,17 @@ func compileInt2(ctx *compileContext, isPtr bool) (*IntCode, error) {
}
func compileInt82(ctx *compileContext, isPtr bool) (*IntCode, error) {
return &IntCode{typ: ctx.typ, bitSize: intSize, isPtr: isPtr}, nil
}
func compileInt162(ctx *compileContext, isPtr bool) (*IntCode, error) {
return &IntCode{typ: ctx.typ, bitSize: 8, isPtr: isPtr}, nil
}
func compileInt322(ctx *compileContext, isPtr bool) (*IntCode, error) {
func compileInt162(ctx *compileContext, isPtr bool) (*IntCode, error) {
return &IntCode{typ: ctx.typ, bitSize: 16, isPtr: isPtr}, nil
}
func compileInt322(ctx *compileContext, isPtr bool) (*IntCode, error) {
return &IntCode{typ: ctx.typ, bitSize: 32, isPtr: isPtr}, nil
}
func compileInt642(ctx *compileContext, isPtr bool) (*IntCode, error) {
return &IntCode{typ: ctx.typ, bitSize: 64, isPtr: isPtr}, nil
}
@ -974,17 +979,17 @@ func compileUint2(ctx *compileContext, isPtr bool) (*UintCode, error) {
}
func compileUint82(ctx *compileContext, isPtr bool) (*UintCode, error) {
return &UintCode{typ: ctx.typ, bitSize: intSize, isPtr: isPtr}, nil
}
func compileUint162(ctx *compileContext, isPtr bool) (*UintCode, error) {
return &UintCode{typ: ctx.typ, bitSize: 8, isPtr: isPtr}, nil
}
func compileUint322(ctx *compileContext, isPtr bool) (*UintCode, error) {
func compileUint162(ctx *compileContext, isPtr bool) (*UintCode, error) {
return &UintCode{typ: ctx.typ, bitSize: 16, isPtr: isPtr}, nil
}
func compileUint322(ctx *compileContext, isPtr bool) (*UintCode, error) {
return &UintCode{typ: ctx.typ, bitSize: 32, isPtr: isPtr}, nil
}
func compileUint642(ctx *compileContext, isPtr bool) (*UintCode, error) {
return &UintCode{typ: ctx.typ, bitSize: 64, isPtr: isPtr}, nil
}
@ -1002,17 +1007,17 @@ func compileIntString2(ctx *compileContext) (*IntCode, error) {
}
func compileInt8String2(ctx *compileContext) (*IntCode, error) {
return &IntCode{typ: ctx.typ, bitSize: intSize, isString: true}, nil
}
func compileInt16String2(ctx *compileContext) (*IntCode, error) {
return &IntCode{typ: ctx.typ, bitSize: 8, isString: true}, nil
}
func compileInt32String2(ctx *compileContext) (*IntCode, error) {
func compileInt16String2(ctx *compileContext) (*IntCode, error) {
return &IntCode{typ: ctx.typ, bitSize: 16, isString: true}, nil
}
func compileInt32String2(ctx *compileContext) (*IntCode, error) {
return &IntCode{typ: ctx.typ, bitSize: 32, isString: true}, nil
}
func compileInt64String2(ctx *compileContext) (*IntCode, error) {
return &IntCode{typ: ctx.typ, bitSize: 64, isString: true}, nil
}
@ -1022,17 +1027,17 @@ func compileUintString2(ctx *compileContext) (*UintCode, error) {
}
func compileUint8String2(ctx *compileContext) (*UintCode, error) {
return &UintCode{typ: ctx.typ, bitSize: intSize, isString: true}, nil
}
func compileUint16String2(ctx *compileContext) (*UintCode, error) {
return &UintCode{typ: ctx.typ, bitSize: 8, isString: true}, nil
}
func compileUint32String2(ctx *compileContext) (*UintCode, error) {
func compileUint16String2(ctx *compileContext) (*UintCode, error) {
return &UintCode{typ: ctx.typ, bitSize: 16, isString: true}, nil
}
func compileUint32String2(ctx *compileContext) (*UintCode, error) {
return &UintCode{typ: ctx.typ, bitSize: 32, isString: true}, nil
}
func compileUint64String2(ctx *compileContext) (*UintCode, error) {
return &UintCode{typ: ctx.typ, bitSize: 64, isString: true}, nil
}

View File

@ -102,11 +102,14 @@ func compileHead(ctx *compileContext) (*Opcode, error) {
return nil, err
}
//pp.Println(code)
newCtx := *ctx
codes := code.ToOpcode(&newCtx)
codes.Last().Next = newEndOp(ctx)
//pp.Println(codes)
derefctx := *ctx
newCtx := &derefctx
codes := code.ToOpcode(newCtx)
codes.Last().Next = newEndOp(newCtx)
//pp.Println(codes.First())
fmt.Println(codes.First().Dump())
linkRecursiveCode2(newCtx)
return codes.First(), nil
typ := ctx.typ
switch {

View File

@ -25,6 +25,8 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
typ: copiedType,
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
structTypeToCode: map[uintptr]*StructCode{},
structTypeToCodes: map[uintptr]Opcodes{},
recursiveCodes: &Opcodes{},
})
if err != nil {
return nil, err
@ -33,6 +35,8 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
typ: copiedType,
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
structTypeToCode: map[uintptr]*StructCode{},
structTypeToCodes: map[uintptr]Opcodes{},
recursiveCodes: &Opcodes{},
escapeKey: true,
})
if err != nil {

View File

@ -31,6 +31,8 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
typ: copiedType,
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
structTypeToCode: map[uintptr]*StructCode{},
structTypeToCodes: map[uintptr]Opcodes{},
recursiveCodes: &Opcodes{},
})
if err != nil {
return nil, err
@ -39,6 +41,8 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
typ: copiedType,
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
structTypeToCode: map[uintptr]*StructCode{},
structTypeToCodes: map[uintptr]Opcodes{},
recursiveCodes: &Opcodes{},
escapeKey: true,
})
if err != nil {

View File

@ -16,6 +16,8 @@ type compileContext struct {
escapeKey bool
structTypeToCompiledCode map[uintptr]*CompiledCode
structTypeToCode map[uintptr]*StructCode
structTypeToCodes map[uintptr]Opcodes
recursiveCodes *Opcodes
parent *compileContext
}
@ -29,6 +31,8 @@ func (c *compileContext) context() *compileContext {
escapeKey: c.escapeKey,
structTypeToCompiledCode: c.structTypeToCompiledCode,
structTypeToCode: c.structTypeToCode,
structTypeToCodes: c.structTypeToCodes,
recursiveCodes: c.recursiveCodes,
parent: c,
}
}

View File

@ -2,6 +2,7 @@ package json_test
import (
"bytes"
"fmt"
"testing"
"github.com/goccy/go-json"
@ -1881,19 +1882,21 @@ func TestCoverMap(t *testing.T) {
for _, test := range tests {
for _, indent := range []bool{true, false} {
for _, htmlEscape := range []bool{true, false} {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(htmlEscape)
if indent {
enc.SetIndent("", " ")
}
if err := enc.Encode(test.data); err != nil {
t.Fatalf("%s(htmlEscape:%v,indent:%v): %+v: %s", test.name, htmlEscape, indent, test.data, err)
}
stdresult := encodeByEncodingJSON(test.data, indent, htmlEscape)
if buf.String() != stdresult {
t.Errorf("%s(htmlEscape:%v,indent:%v): doesn't compatible with encoding/json. expected %q but got %q", test.name, htmlEscape, indent, stdresult, buf.String())
}
t.Run(fmt.Sprintf("%s_indent_%t_escape_%t", test.name, indent, htmlEscape), func(t *testing.T) {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(htmlEscape)
if indent {
enc.SetIndent("", " ")
}
if err := enc.Encode(test.data); err != nil {
t.Fatalf("%s(htmlEscape:%v,indent:%v): %+v: %s", test.name, htmlEscape, indent, test.data, err)
}
stdresult := encodeByEncodingJSON(test.data, indent, htmlEscape)
if buf.String() != stdresult {
t.Errorf("%s(htmlEscape:%v,indent:%v): doesn't compatible with encoding/json. expected %q but got %q", test.name, htmlEscape, indent, stdresult, buf.String())
}
})
}
}
}

View File

@ -2,6 +2,7 @@ package json_test
import (
"bytes"
"fmt"
"testing"
"github.com/goccy/go-json"
@ -2047,9 +2048,9 @@ func TestCoverSlice(t *testing.T) {
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
for _, indent := range []bool{true, false} {
for _, htmlEscape := range []bool{true, false} {
for _, indent := range []bool{true, false} {
for _, htmlEscape := range []bool{true, false} {
t.Run(fmt.Sprintf("%s_indent_%t_escape_%t", test.name, indent, htmlEscape), func(t *testing.T) {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(htmlEscape)
@ -2063,8 +2064,8 @@ func TestCoverSlice(t *testing.T) {
if buf.String() != stdresult {
t.Errorf("%s(htmlEscape:%v,indent:%v): doesn't compatible with encoding/json. expected %q but got %q", test.name, htmlEscape, indent, stdresult, buf.String())
}
}
})
}
})
}
}
}