Jelajahi Sumber

optimize slice

Tao Wen 9 tahun lalu
induk
melakukan
71cdbd249c
2 mengubah file dengan 68 tambahan dan 14 penghapusan
  1. 43 7
      jsoniter_reflect.go
  2. 25 7
      jsoniter_reflect_test.go

+ 43 - 7
jsoniter_reflect.go

@@ -308,16 +308,43 @@ type sliceHeader struct {
 }
 
 func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	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)
-	slice.Len = 0
+	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() {
-		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 {
-		iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
+		offset += decoder.elemType.Size()
+		decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
 	}
 }
 
@@ -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) {

+ 25 - 7
jsoniter_reflect_test.go

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