when cap is enough, reuse slice data for compatibility with encoding/json

This commit is contained in:
IncSW 2021-04-30 19:09:15 +03:00
parent 4d51b8b764
commit 2ad2f11326
No known key found for this signature in database
GPG Key ID: 89876FA64BFB2D57
2 changed files with 28 additions and 18 deletions

View File

@ -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,

View File

@ -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))