Explorar o código

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

Tao Wen %!s(int64=8) %!d(string=hai) anos
pai
achega
dc44e85a86

+ 8 - 4
feature_reflect_array.go

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

+ 0 - 1
feature_reflect_map.go

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

+ 14 - 0
feature_reflect_object.go

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

+ 62 - 0
jsoniter_interface_test.go

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

+ 0 - 23
jsoniter_object_test.go

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