From 2ad2f11326680522a8cab68c7703912c4d5e5937 Mon Sep 17 00:00:00 2001 From: IncSW Date: Fri, 30 Apr 2021 19:09:15 +0300 Subject: [PATCH] when cap is enough, reuse slice data for compatibility with encoding/json --- decode_slice.go | 36 ++++++++++++++++++++---------------- decode_test.go | 10 ++++++++-- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/decode_slice.go b/decode_slice.go index ea09f88..a80307e 100644 --- a/decode_slice.go +++ b/decode_slice.go @@ -96,10 +96,11 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er s.cursor++ s.skipWhiteSpace() if s.char() == ']' { - *(*sliceHeader)(p) = sliceHeader{ - data: newArray(d.elemType, 0), - len: 0, - cap: 0, + dst := (*sliceHeader)(p) + if dst.data == nil { + dst.data = newArray(d.elemType, 0) + } else { + dst.len = 0 } s.cursor++ return nil @@ -130,11 +131,12 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er slice.cap = capacity slice.len = idx + 1 slice.data = data + dst := *(*sliceHeader)(p) + dst.len = idx + 1 dstCap := idx + 1 - dst := sliceHeader{ - data: newArray(d.elemType, dstCap), - len: idx + 1, - cap: dstCap, + if dstCap > dst.cap { + dst.data = newArray(d.elemType, dstCap) + dst.cap = dstCap } copySlice(d.elemType, dst, sliceHeader{ data: slice.data, @@ -210,10 +212,11 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) cursor++ cursor = skipWhiteSpace(buf, cursor) if buf[cursor] == ']' { - **(**sliceHeader)(unsafe.Pointer(&p)) = sliceHeader{ - data: newArray(d.elemType, 0), - len: 0, - cap: 0, + dst := (*sliceHeader)(p) + if dst.data == nil { + dst.data = newArray(d.elemType, 0) + } else { + dst.len = 0 } cursor++ return cursor, nil @@ -245,11 +248,12 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) slice.cap = capacity slice.len = idx + 1 slice.data = data + dst := *(*sliceHeader)(p) + dst.len = idx + 1 dstCap := idx + 1 - dst := sliceHeader{ - data: newArray(d.elemType, dstCap), - len: idx + 1, - cap: dstCap, + if dstCap > dst.cap { + dst.data = newArray(d.elemType, dstCap) + dst.cap = dstCap } copySlice(d.elemType, dst, sliceHeader{ data: slice.data, diff --git a/decode_test.go b/decode_test.go index 574341f..2eb01d9 100644 --- a/decode_test.go +++ b/decode_test.go @@ -103,6 +103,12 @@ func Test_Decoder(t *testing.T) { assertErr(t, json.Unmarshal([]byte(` [ 1 , 2 , 3 , 4 ] `), &v)) assertEq(t, "slice", fmt.Sprint([]int{1, 2, 3, 4}), fmt.Sprint(v)) }) + t.Run("slice_reuse_data", func(t *testing.T) { + v := make([]int, 0, 10) + assertErr(t, json.Unmarshal([]byte(` [ 1 , 2 , 3 , 4 ] `), &v)) + assertEq(t, "slice", fmt.Sprint([]int{1, 2, 3, 4}), fmt.Sprint(v)) + assertEq(t, "cap", 10, cap(v)) + }) t.Run("array", func(t *testing.T) { var v [4]int assertErr(t, json.Unmarshal([]byte(` [ 1 , 2 , 3 , 4 ] `), &v)) @@ -121,10 +127,10 @@ func Test_Decoder(t *testing.T) { { "a": { "nestedA": "value of nested a" - }, + }, "b": { "nestedB": "value of nested b" - }, + }, "c": { "nestedC": "value of nested c" }