Merge pull request #200 from IncSW/slice-decoding-compatibility

when cap is enough, reuse slice data for compatibility with encoding/json
This commit is contained in:
Masaaki Goshima 2021-05-03 17:11:43 +09:00 committed by GitHub
commit 51905367ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 32 deletions

View File

@ -101,10 +101,11 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
s.cursor++ s.cursor++
s.skipWhiteSpace() s.skipWhiteSpace()
if s.char() == ']' { if s.char() == ']' {
*(*sliceHeader)(p) = sliceHeader{ dst := (*sliceHeader)(p)
data: newArray(d.elemType, 0), if dst.data == nil {
len: 0, dst.data = newArray(d.elemType, 0)
cap: 0, } else {
dst.len = 0
} }
s.cursor++ s.cursor++
return nil return nil
@ -138,18 +139,13 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
slice.cap = capacity slice.cap = capacity
slice.len = idx + 1 slice.len = idx + 1
slice.data = data slice.data = data
dstCap := idx + 1 dst := (*sliceHeader)(p)
dst := sliceHeader{ dst.len = idx + 1
data: newArray(d.elemType, dstCap), if dst.len > dst.cap {
len: idx + 1, dst.data = newArray(d.elemType, dst.len)
cap: dstCap, dst.cap = dst.len
} }
copySlice(d.elemType, dst, sliceHeader{ copySlice(d.elemType, *dst, *slice)
data: slice.data,
len: slice.len,
cap: slice.cap,
})
*(*sliceHeader)(p) = dst
d.releaseSlice(slice) d.releaseSlice(slice)
s.cursor++ s.cursor++
return nil return nil
@ -218,10 +214,11 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
cursor++ cursor++
cursor = skipWhiteSpace(buf, cursor) cursor = skipWhiteSpace(buf, cursor)
if buf[cursor] == ']' { if buf[cursor] == ']' {
**(**sliceHeader)(unsafe.Pointer(&p)) = sliceHeader{ dst := (*sliceHeader)(p)
data: newArray(d.elemType, 0), if dst.data == nil {
len: 0, dst.data = newArray(d.elemType, 0)
cap: 0, } else {
dst.len = 0
} }
cursor++ cursor++
return cursor, nil return cursor, nil
@ -256,18 +253,13 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
slice.cap = capacity slice.cap = capacity
slice.len = idx + 1 slice.len = idx + 1
slice.data = data slice.data = data
dstCap := idx + 1 dst := (*sliceHeader)(p)
dst := sliceHeader{ dst.len = idx + 1
data: newArray(d.elemType, dstCap), if dst.len > dst.cap {
len: idx + 1, dst.data = newArray(d.elemType, dst.len)
cap: dstCap, dst.cap = dst.len
} }
copySlice(d.elemType, dst, sliceHeader{ copySlice(d.elemType, *dst, *slice)
data: slice.data,
len: slice.len,
cap: slice.cap,
})
**(**sliceHeader)(unsafe.Pointer(&p)) = dst
d.releaseSlice(slice) d.releaseSlice(slice)
cursor++ cursor++
return cursor, nil return cursor, nil

View File

@ -103,6 +103,12 @@ func Test_Decoder(t *testing.T) {
assertErr(t, json.Unmarshal([]byte(` [ 1 , 2 , 3 , 4 ] `), &v)) 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, "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) { t.Run("array", func(t *testing.T) {
var v [4]int var v [4]int
assertErr(t, json.Unmarshal([]byte(` [ 1 , 2 , 3 , 4 ] `), &v)) assertErr(t, json.Unmarshal([]byte(` [ 1 , 2 , 3 , 4 ] `), &v))
@ -121,10 +127,10 @@ func Test_Decoder(t *testing.T) {
{ {
"a": { "a": {
"nestedA": "value of nested a" "nestedA": "value of nested a"
}, },
"b": { "b": {
"nestedB": "value of nested b" "nestedB": "value of nested b"
}, },
"c": { "c": {
"nestedC": "value of nested c" "nestedC": "value of nested c"
} }