mirror of
https://github.com/json-iterator/go.git
synced 2025-05-16 21:45:43 +02:00
#73 fix interface{} optimization for one ptr field struct and array
This commit is contained in:
parent
85f7a1b0b3
commit
dc44e85a86
@ -33,10 +33,6 @@ type arrayEncoder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||||
if ptr == nil {
|
|
||||||
stream.WriteNil()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
stream.WriteArrayStart()
|
stream.WriteArrayStart()
|
||||||
elemPtr := uintptr(ptr)
|
elemPtr := uintptr(ptr)
|
||||||
encoder.elemEncoder.Encode(unsafe.Pointer(elemPtr), stream)
|
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) {
|
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)
|
WriteToStream(val, stream, encoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,6 @@ func (encoder *mapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
|||||||
mapInterface.word = ptr
|
mapInterface.word = ptr
|
||||||
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
|
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
|
||||||
realVal := reflect.ValueOf(*realInterface)
|
realVal := reflect.ValueOf(*realInterface)
|
||||||
|
|
||||||
stream.WriteObjectStart()
|
stream.WriteObjectStart()
|
||||||
for i, key := range realVal.MapKeys() {
|
for i, key := range realVal.MapKeys() {
|
||||||
if i != 0 {
|
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)
|
WriteToStream(val, stream, encoderToUse)
|
||||||
|
@ -162,3 +162,65 @@ func Test_read_large_number_as_interface(t *testing.T) {
|
|||||||
should.Nil(err)
|
should.Nil(err)
|
||||||
should.Equal(`123456789123456789123456789`, output)
|
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)
|
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) {
|
func Test_encode_anonymous_struct(t *testing.T) {
|
||||||
should := require.New(t)
|
should := require.New(t)
|
||||||
type TestObject struct {
|
type TestObject struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user