1
0
mirror of https://github.com/json-iterator/go.git synced 2025-03-29 21:20:52 +02:00

fix interface{} optimization for one ptr field struct and array

This commit is contained in:
Tao Wen 2017-06-26 22:37:24 +08:00
parent 85f7a1b0b3
commit dc44e85a86
5 changed files with 84 additions and 28 deletions

@ -33,10 +33,6 @@ type arrayEncoder struct {
}
func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
if ptr == nil {
stream.WriteNil()
return
}
stream.WriteArrayStart()
elemPtr := uintptr(ptr)
encoder.elemEncoder.Encode(unsafe.Pointer(elemPtr), stream)
@ -52,6 +48,14 @@ func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *arrayEncoder) EncodeInterface(val interface{}, stream *Stream) {
// special optimization for interface{}
e := (*emptyInterface)(unsafe.Pointer(&val))
if e.word == nil {
stream.WriteArrayStart()
stream.WriteNil()
stream.WriteArrayEnd()
return
}
WriteToStream(val, stream, encoder)
}

@ -85,7 +85,6 @@ func (encoder *mapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface)
stream.WriteObjectStart()
for i, key := range realVal.MapKeys() {
if i != 0 {

@ -1039,6 +1039,20 @@ func (encoder *structEncoder) EncodeInterface(val interface{}, stream *Stream) {
},
},
}
e := (*emptyInterface)(unsafe.Pointer(&val))
if e.word == nil {
stream.WriteObjectStart()
stream.WriteObjectField(firstFieldName)
stream.WriteNil()
stream.WriteObjectEnd()
return
}
if reflect.TypeOf(val).Kind() == reflect.Ptr {
encoderToUse.Encode(unsafe.Pointer(&e.word), stream)
} else {
encoderToUse.Encode(e.word, stream)
}
return
}
}
WriteToStream(val, stream, encoderToUse)

@ -162,3 +162,65 @@ func Test_read_large_number_as_interface(t *testing.T) {
should.Nil(err)
should.Equal(`123456789123456789123456789`, output)
}
func Test_nested_one_field_struct(t *testing.T) {
should := require.New(t)
type YetYetAnotherObject struct {
Field string
}
type YetAnotherObject struct {
Field *YetYetAnotherObject
}
type AnotherObject struct {
Field *YetAnotherObject
}
type TestObject struct {
Me *AnotherObject
}
obj := TestObject{&AnotherObject{&YetAnotherObject{&YetYetAnotherObject{"abc"}}}}
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
str, err = MarshalToString(&obj)
should.Nil(err)
should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
}
func Test_struct_with_one_nil(t *testing.T) {
type TestObject struct {
F *float64
}
var obj TestObject
should := require.New(t)
output, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"F":null}`, output)
}
func Test_array_with_one_nil(t *testing.T) {
obj := [1]*float64{nil}
should := require.New(t)
output, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`[null]`, output)
}
func Test_embedded_array_with_one_nil(t *testing.T) {
type TestObject struct {
Field1 int
Field2 [1]*float64
}
var obj TestObject
should := require.New(t)
output, err := MarshalToString(obj)
should.Nil(err)
should.Contains(output, `"Field2":[null]`)
}
func Test_array_with_nothing(t *testing.T) {
var obj [2]*float64
should := require.New(t)
output, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`[null,null]`, output)
}

@ -280,29 +280,6 @@ func Test_recursive_struct(t *testing.T) {
should.Nil(err)
}
func Test_one_field_struct(t *testing.T) {
should := require.New(t)
type YetYetAnotherObject struct {
Field string
}
type YetAnotherObject struct {
Field *YetYetAnotherObject
}
type AnotherObject struct {
Field *YetAnotherObject
}
type TestObject struct {
Me *AnotherObject
}
obj := TestObject{&AnotherObject{&YetAnotherObject{&YetYetAnotherObject{"abc"}}}}
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
str, err = MarshalToString(&obj)
should.Nil(err)
should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
}
func Test_encode_anonymous_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {