mirror of
https://github.com/json-iterator/go.git
synced 2025-05-13 21:36:29 +02:00
optimize slice
This commit is contained in:
parent
87a35bd7e4
commit
71cdbd249c
@ -308,19 +308,46 @@ type sliceHeader struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
slice := (*sliceHeader)(ptr)
|
decoder.doDecode(ptr, iter)
|
||||||
slice.Len = 0
|
|
||||||
for iter.ReadArray() {
|
|
||||||
offset := uintptr(slice.Len) * decoder.elemType.Size()
|
|
||||||
growOne(slice, decoder.sliceType, decoder.elemType)
|
|
||||||
dataPtr := uintptr(slice.Data) + offset
|
|
||||||
decoder.elemDecoder.decode(unsafe.Pointer(dataPtr), iter)
|
|
||||||
}
|
|
||||||
if iter.Error != nil && iter.Error != io.EOF {
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
|
iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
slice := (*sliceHeader)(ptr)
|
||||||
|
reuseSlice(slice, decoder.sliceType, 4)
|
||||||
|
if !iter.ReadArray() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offset := uintptr(0)
|
||||||
|
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
||||||
|
if !iter.ReadArray() {
|
||||||
|
slice.Len = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offset += decoder.elemType.Size()
|
||||||
|
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
||||||
|
if !iter.ReadArray() {
|
||||||
|
slice.Len = 2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offset += decoder.elemType.Size()
|
||||||
|
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
||||||
|
if !iter.ReadArray() {
|
||||||
|
slice.Len = 3
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offset += decoder.elemType.Size()
|
||||||
|
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
||||||
|
slice.Len = 4
|
||||||
|
for iter.ReadArray() {
|
||||||
|
growOne(slice, decoder.sliceType, decoder.elemType)
|
||||||
|
offset += decoder.elemType.Size()
|
||||||
|
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// grow grows the slice s so that it can hold extra more values, allocating
|
// grow grows the slice s so that it can hold extra more values, allocating
|
||||||
// more capacity if needed. It also returns the old and new slice lengths.
|
// more capacity if needed. It also returns the old and new slice lengths.
|
||||||
func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
|
func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
|
||||||
@ -353,6 +380,15 @@ func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Typ
|
|||||||
slice.Data = dst
|
slice.Data = dst
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
|
||||||
|
if expectedCap <= slice.Cap {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, 0, expectedCap).Pointer())
|
||||||
|
slice.Cap = expectedCap
|
||||||
|
slice.Data = dst
|
||||||
|
}
|
||||||
|
|
||||||
var DECODERS unsafe.Pointer
|
var DECODERS unsafe.Pointer
|
||||||
|
|
||||||
func addDecoderToCache(cacheKey string, decoder Decoder) {
|
func addDecoderToCache(cacheKey string, decoder Decoder) {
|
||||||
|
@ -218,7 +218,7 @@ func Test_reflect_struct_tag_field(t *testing.T) {
|
|||||||
|
|
||||||
func Test_reflect_slice(t *testing.T) {
|
func Test_reflect_slice(t *testing.T) {
|
||||||
iter := ParseString(`["hello", "world"]`)
|
iter := ParseString(`["hello", "world"]`)
|
||||||
slice := make([]string, 0, 1)
|
slice := make([]string, 0, 5)
|
||||||
iter.Read(&slice)
|
iter.Read(&slice)
|
||||||
if len(slice) != 2 {
|
if len(slice) != 2 {
|
||||||
fmt.Println(iter.Error)
|
fmt.Println(iter.Error)
|
||||||
@ -234,6 +234,24 @@ func Test_reflect_slice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_reflect_large_slice(t *testing.T) {
|
||||||
|
iter := ParseString(`[1,2,3,4,5,6,7,8,9]`)
|
||||||
|
slice := make([]int, 0, 1)
|
||||||
|
iter.Read(&slice)
|
||||||
|
if len(slice) != 9 {
|
||||||
|
fmt.Println(iter.Error)
|
||||||
|
t.Fatal(len(slice))
|
||||||
|
}
|
||||||
|
if slice[0] != 1 {
|
||||||
|
fmt.Println(iter.Error)
|
||||||
|
t.Fatal(slice[0])
|
||||||
|
}
|
||||||
|
if slice[8] != 9 {
|
||||||
|
fmt.Println(iter.Error)
|
||||||
|
t.Fatal(slice[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_reflect_nested(t *testing.T) {
|
func Test_reflect_nested(t *testing.T) {
|
||||||
iter := ParseString(`[{"field1": "hello"}, null, {"field2": "world"}]`)
|
iter := ParseString(`[{"field1": "hello"}, null, {"field2": "world"}]`)
|
||||||
slice := []*StructOfString{}
|
slice := []*StructOfString{}
|
||||||
@ -267,12 +285,12 @@ type StructOfTagOne struct {
|
|||||||
func Benchmark_jsoniter_reflect(b *testing.B) {
|
func Benchmark_jsoniter_reflect(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
iter := ParseString(`{"field3": "100"}`)
|
//iter := ParseString(`{"field3": "100"}`)
|
||||||
struct_ := StructOfTagOne{}
|
//struct_ := StructOfTagOne{}
|
||||||
iter.Read(&struct_)
|
//iter.Read(&struct_)
|
||||||
//iter := ParseString(`["hello", "world"]`)
|
iter := ParseString(`[1,2,3]`)
|
||||||
//array := make([]string, 0, 1)
|
var array []int
|
||||||
//iter.Read(&array)
|
iter.Read(&array)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user