diff --git a/decode_slice.go b/decode_slice.go index d0be101..b00a2bb 100644 --- a/decode_slice.go +++ b/decode_slice.go @@ -101,10 +101,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 @@ -138,18 +139,13 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er slice.cap = capacity slice.len = idx + 1 slice.data = data - dstCap := idx + 1 - dst := sliceHeader{ - data: newArray(d.elemType, dstCap), - len: idx + 1, - cap: dstCap, + dst := (*sliceHeader)(p) + dst.len = idx + 1 + if dst.len > dst.cap { + dst.data = newArray(d.elemType, dst.len) + dst.cap = dst.len } - copySlice(d.elemType, dst, sliceHeader{ - data: slice.data, - len: slice.len, - cap: slice.cap, - }) - *(*sliceHeader)(p) = dst + copySlice(d.elemType, *dst, *slice) d.releaseSlice(slice) s.cursor++ return nil @@ -218,10 +214,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 @@ -256,18 +253,13 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) slice.cap = capacity slice.len = idx + 1 slice.data = data - dstCap := idx + 1 - dst := sliceHeader{ - data: newArray(d.elemType, dstCap), - len: idx + 1, - cap: dstCap, + dst := (*sliceHeader)(p) + dst.len = idx + 1 + if dst.len > dst.cap { + dst.data = newArray(d.elemType, dst.len) + dst.cap = dst.len } - copySlice(d.elemType, dst, sliceHeader{ - data: slice.data, - len: slice.len, - cap: slice.cap, - }) - **(**sliceHeader)(unsafe.Pointer(&p)) = dst + copySlice(d.elemType, *dst, *slice) d.releaseSlice(slice) cursor++ return cursor, nil diff --git a/decode_test.go b/decode_test.go index fb4ea65..002a8eb 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" }