From 99a5b20e5e4a5b194036fff4127118fedac83f97 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Tue, 25 Aug 2020 17:18:37 +0900 Subject: [PATCH 1/3] Fix decoding of recursive type --- decode.go | 8 ++++++-- decode_compile.go | 9 ++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/decode.go b/decode.go index d092057..56b9c24 100644 --- a/decode.go +++ b/decode.go @@ -23,6 +23,7 @@ type decoder interface { type Decoder struct { s *stream disallowUnknownFields bool + structTypeToDecoder map[uintptr]decoder } type decoderMap struct { @@ -61,7 +62,9 @@ const ( func NewDecoder(r io.Reader) *Decoder { s := &stream{r: r} s.read() - return &Decoder{s: s} + return &Decoder{ + s: s, + } } // Buffered returns a reader of the data remaining in the Decoder's @@ -90,7 +93,7 @@ func (d *Decoder) decode(src []byte, header *interfaceHeader) error { } dec := cachedDecoder.get(typeptr) if dec == nil { - + d.structTypeToDecoder = map[uintptr]decoder{} compiledDec, err := d.compileHead(copiedType) if err != nil { return err @@ -155,6 +158,7 @@ func (d *Decoder) Decode(v interface{}) error { dec := cachedDecoder.get(typeptr) if dec == nil { + d.structTypeToDecoder = map[uintptr]decoder{} compiledDec, err := d.compileHead(typ) if err != nil { return err diff --git a/decode_compile.go b/decode_compile.go index bb6ab06..1ed11aa 100644 --- a/decode_compile.go +++ b/decode_compile.go @@ -204,6 +204,12 @@ func (d *Decoder) compileInterface(typ *rtype) (decoder, error) { func (d *Decoder) compileStruct(typ *rtype) (decoder, error) { fieldNum := typ.NumField() fieldMap := map[string]*structFieldSet{} + typeptr := uintptr(unsafe.Pointer(typ)) + if dec, exists := d.structTypeToDecoder[typeptr]; exists { + return dec, nil + } + structDec := newStructDecoder(fieldMap) + d.structTypeToDecoder[typeptr] = structDec for i := 0; i < fieldNum; i++ { field := typ.Field(i) if isIgnoredStructField(field) { @@ -222,5 +228,6 @@ func (d *Decoder) compileStruct(typ *rtype) (decoder, error) { fieldMap[tag.key] = fieldSet fieldMap[strings.ToLower(tag.key)] = fieldSet } - return newStructDecoder(fieldMap), nil + delete(d.structTypeToDecoder, typeptr) + return structDec, nil } From 6681db131f0cf5810d67f4a92ad8d85fef4a12ca Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Tue, 25 Aug 2020 17:19:19 +0900 Subject: [PATCH 2/3] Fix StructFieldHead operation --- encode_vm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encode_vm.go b/encode_vm.go index b9f4eaf..a9ebb3b 100644 --- a/encode_vm.go +++ b/encode_vm.go @@ -550,7 +550,7 @@ func (e *Encoder) run(code *opcode) error { e.encodeBytes(field.key) } code = field.next - code.ptr = ptr + code.ptr = ptr + field.offset field.nextField.ptr = ptr } case opStructFieldAnonymousHead: From e28091e4c7d8285aaac78e7a093f64ac92ba2e13 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Tue, 25 Aug 2020 17:19:41 +0900 Subject: [PATCH 3/3] Improve performance for []byte type --- encode_vm.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/encode_vm.go b/encode_vm.go index a9ebb3b..8714a4c 100644 --- a/encode_vm.go +++ b/encode_vm.go @@ -74,9 +74,12 @@ func (e *Encoder) run(code *opcode) error { if ptr == 0 || header.Data == 0 { e.encodeNull() } else { - s := base64.StdEncoding.EncodeToString(e.ptrToBytes(code.ptr)) + b := e.ptrToBytes(code.ptr) + encodedLen := base64.StdEncoding.EncodedLen(len(b)) e.encodeByte('"') - e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s))) + buf := make([]byte, encodedLen) + base64.StdEncoding.Encode(buf, b) + e.encodeBytes(buf) e.encodeByte('"') } code = code.next