소스 검색

optimize struct reflect

Tao Wen 9 년 전
부모
커밋
87a35bd7e4
2개의 변경된 파일197개의 추가작업 그리고 5개의 파일을 삭제
  1. 187 2
      jsoniter_reflect.go
  2. 10 3
      jsoniter_reflect_test.go

+ 187 - 2
jsoniter_reflect.go

@@ -149,7 +149,7 @@ func (decoder *optionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
 }
 
 type structDecoder struct {
-	type_ reflect.Type
+	type_  reflect.Type
 	fields map[string]Decoder
 }
 
@@ -167,8 +167,122 @@ func (decoder *structDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
 	}
 }
 
+type skipDecoder struct {
+	type_ reflect.Type
+}
+
+func (decoder *skipDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	iter.Skip()
+	if iter.Error != nil && iter.Error != io.EOF {
+		iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
+	}
+}
+
+type oneFieldStructDecoder struct {
+	type_        reflect.Type
+	fieldName    string
+	fieldDecoder Decoder
+}
+
+func (decoder *oneFieldStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
+		if field == decoder.fieldName {
+			decoder.fieldDecoder.decode(ptr, iter)
+		} else {
+			iter.Skip()
+		}
+	}
+	if iter.Error != nil && iter.Error != io.EOF {
+		iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
+	}
+}
+
+type twoFieldsStructDecoder struct {
+	type_         reflect.Type
+	fieldName1    string
+	fieldDecoder1 Decoder
+	fieldName2    string
+	fieldDecoder2 Decoder
+}
+
+func (decoder *twoFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
+		switch field {
+		case decoder.fieldName1:
+			decoder.fieldDecoder1.decode(ptr, iter)
+		case decoder.fieldName2:
+			decoder.fieldDecoder2.decode(ptr, iter)
+		default:
+			iter.Skip()
+		}
+	}
+	if iter.Error != nil && iter.Error != io.EOF {
+		iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
+	}
+}
+
+type threeFieldsStructDecoder struct {
+	type_         reflect.Type
+	fieldName1    string
+	fieldDecoder1 Decoder
+	fieldName2    string
+	fieldDecoder2 Decoder
+	fieldName3    string
+	fieldDecoder3 Decoder
+}
+
+func (decoder *threeFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
+		switch field {
+		case decoder.fieldName1:
+			decoder.fieldDecoder1.decode(ptr, iter)
+		case decoder.fieldName2:
+			decoder.fieldDecoder2.decode(ptr, iter)
+		case decoder.fieldName3:
+			decoder.fieldDecoder3.decode(ptr, iter)
+		default:
+			iter.Skip()
+		}
+	}
+	if iter.Error != nil && iter.Error != io.EOF {
+		iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
+	}
+}
+
+type fourFieldsStructDecoder struct {
+	type_         reflect.Type
+	fieldName1    string
+	fieldDecoder1 Decoder
+	fieldName2    string
+	fieldDecoder2 Decoder
+	fieldName3    string
+	fieldDecoder3 Decoder
+	fieldName4    string
+	fieldDecoder4 Decoder
+}
+
+func (decoder *fourFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
+		switch field {
+		case decoder.fieldName1:
+			decoder.fieldDecoder1.decode(ptr, iter)
+		case decoder.fieldName2:
+			decoder.fieldDecoder2.decode(ptr, iter)
+		case decoder.fieldName3:
+			decoder.fieldDecoder3.decode(ptr, iter)
+		case decoder.fieldName4:
+			decoder.fieldDecoder4.decode(ptr, iter)
+		default:
+			iter.Skip()
+		}
+	}
+	if iter.Error != nil && iter.Error != io.EOF {
+		iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
+	}
+}
+
 type structFieldDecoder struct {
-	field       *reflect.StructField
+	field        *reflect.StructField
 	fieldDecoder Decoder
 }
 
@@ -412,6 +526,77 @@ func decoderOfStruct(type_ reflect.Type) (Decoder, error) {
 			fields[jsonFieldName] = &structFieldDecoder{&field, decoder}
 		}
 	}
+	switch len(fields) {
+	case 0:
+		return &skipDecoder{type_}, nil
+	case 1:
+		for fieldName, fieldDecoder := range fields {
+			return &oneFieldStructDecoder{type_, fieldName, fieldDecoder}, nil
+		}
+	case 2:
+		var fieldName1 string
+		var fieldName2 string
+		var fieldDecoder1 Decoder
+		var fieldDecoder2 Decoder
+		for fieldName, fieldDecoder := range fields {
+			if fieldName1 == "" {
+				fieldName1 = fieldName
+				fieldDecoder1 = fieldDecoder
+			} else {
+				fieldName2 = fieldName
+				fieldDecoder2 = fieldDecoder
+			}
+		}
+		return &twoFieldsStructDecoder{type_, fieldName1, fieldDecoder1, fieldName2, fieldDecoder2}, nil
+	case 3:
+		var fieldName1 string
+		var fieldName2 string
+		var fieldName3 string
+		var fieldDecoder1 Decoder
+		var fieldDecoder2 Decoder
+		var fieldDecoder3 Decoder
+		for fieldName, fieldDecoder := range fields {
+			if fieldName1 == "" {
+				fieldName1 = fieldName
+				fieldDecoder1 = fieldDecoder
+			} else if fieldName2 == "" {
+				fieldName2 = fieldName
+				fieldDecoder2 = fieldDecoder
+			} else {
+				fieldName3 = fieldName
+				fieldDecoder3 = fieldDecoder
+			}
+		}
+		return &threeFieldsStructDecoder{type_,
+			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
+	case 4:
+		var fieldName1 string
+		var fieldName2 string
+		var fieldName3 string
+		var fieldName4 string
+		var fieldDecoder1 Decoder
+		var fieldDecoder2 Decoder
+		var fieldDecoder3 Decoder
+		var fieldDecoder4 Decoder
+		for fieldName, fieldDecoder := range fields {
+			if fieldName1 == "" {
+				fieldName1 = fieldName
+				fieldDecoder1 = fieldDecoder
+			} else if fieldName2 == "" {
+				fieldName2 = fieldName
+				fieldDecoder2 = fieldDecoder
+			} else if fieldName3 == "" {
+				fieldName3 = fieldName
+				fieldDecoder3 = fieldDecoder
+			} else {
+				fieldName4 = fieldName
+				fieldDecoder4 = fieldDecoder
+			}
+		}
+		return &fourFieldsStructDecoder{type_,
+			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
+			fieldName4, fieldDecoder4}, nil
+	}
 	return &structDecoder{type_, fields}, nil
 }
 

+ 10 - 3
jsoniter_reflect_test.go

@@ -192,7 +192,6 @@ func Test_reflect_struct_string_ptr(t *testing.T) {
 	}
 }
 
-
 type StructOfTag struct {
 	field1 string `json:"field-1"`
 	field2 string `json:"-"`
@@ -257,11 +256,19 @@ func Test_reflect_nested(t *testing.T) {
 	}
 }
 
+
+type StructOfTagOne struct {
+	field1 string `json:"field1"`
+	field2 string `json:"field2"`
+	field3 int `json:"field3,string"`
+	field4 int `json:"field4,string"`
+}
+
 func Benchmark_jsoniter_reflect(b *testing.B) {
 	b.ReportAllocs()
 	for n := 0; n < b.N; n++ {
 		iter := ParseString(`{"field3": "100"}`)
-		struct_ := StructOfTag{}
+		struct_ := StructOfTagOne{}
 		iter.Read(&struct_)
 		//iter := ParseString(`["hello", "world"]`)
 		//array := make([]string, 0, 1)
@@ -295,7 +302,7 @@ func Benchmark_jsoniter_direct(b *testing.B) {
 func Benchmark_json_reflect(b *testing.B) {
 	b.ReportAllocs()
 	for n := 0; n < b.N; n++ {
-		struct_ := StructOfTag{}
+		struct_ := StructOfTagOne{}
 		json.Unmarshal([]byte(`{"field3": "100"}`), &struct_)
 		//array := make([]string, 0, 2)
 		//json.Unmarshal([]byte(`["hello", "world"]`), &array)