1
0
mirror of https://github.com/json-iterator/go.git synced 2025-03-23 21:09:11 +02:00

optimize slice

This commit is contained in:
Tao Wen 2016-12-07 08:49:52 +08:00
parent 87a35bd7e4
commit 71cdbd249c
2 changed files with 69 additions and 15 deletions

@ -308,19 +308,46 @@ type sliceHeader struct {
}
func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
slice := (*sliceHeader)(ptr)
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)
}
decoder.doDecode(ptr, iter)
if iter.Error != nil && iter.Error != io.EOF {
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
// more capacity if needed. It also returns the old and new slice lengths.
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
}
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
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) {
iter := ParseString(`["hello", "world"]`)
slice := make([]string, 0, 1)
slice := make([]string, 0, 5)
iter.Read(&slice)
if len(slice) != 2 {
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) {
iter := ParseString(`[{"field1": "hello"}, null, {"field2": "world"}]`)
slice := []*StructOfString{}
@ -267,12 +285,12 @@ type StructOfTagOne struct {
func Benchmark_jsoniter_reflect(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
iter := ParseString(`{"field3": "100"}`)
struct_ := StructOfTagOne{}
iter.Read(&struct_)
//iter := ParseString(`["hello", "world"]`)
//array := make([]string, 0, 1)
//iter.Read(&array)
//iter := ParseString(`{"field3": "100"}`)
//struct_ := StructOfTagOne{}
//iter.Read(&struct_)
iter := ParseString(`[1,2,3]`)
var array []int
iter.Read(&array)
}
}