1
0
mirror of https://github.com/json-iterator/go.git synced 2025-01-08 13:06:29 +02:00

optimize struct reflect

This commit is contained in:
Tao Wen 2016-12-07 08:20:18 +08:00
parent 42a4f2c11d
commit 87a35bd7e4
2 changed files with 197 additions and 5 deletions

View File

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

View File

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