1
0
mirror of https://github.com/json-iterator/go.git synced 2025-05-13 21:36:29 +02:00

fix one field struct interface{} optimization compatibility

This commit is contained in:
Tao Wen 2017-05-23 17:44:50 +08:00
parent 53f8d370b5
commit 5488fde97f
6 changed files with 174 additions and 193 deletions

View File

@ -27,7 +27,7 @@ type Encoder interface {
encodeInterface(val interface{}, stream *Stream)
}
func WriteToStream(val interface{}, stream *Stream, encoder Encoder) {
func writeToStream(val interface{}, stream *Stream, encoder Encoder) {
e := (*emptyInterface)(unsafe.Pointer(&val))
if reflect.TypeOf(val).Kind() == reflect.Ptr {
encoder.encode(unsafe.Pointer(&e.word), stream)
@ -57,7 +57,7 @@ func (encoder *funcEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *funcEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (encoder *funcEncoder) isEmpty(ptr unsafe.Pointer) bool {
@ -193,7 +193,7 @@ func (encoder *optionalEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *optionalEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (encoder *optionalEncoder) isEmpty(ptr unsafe.Pointer) bool {
@ -213,7 +213,7 @@ func (encoder *placeholderEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *placeholderEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (encoder *placeholderEncoder) isEmpty(ptr unsafe.Pointer) bool {
@ -278,7 +278,7 @@ func (encoder *mapEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *mapEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (encoder *mapEncoder) isEmpty(ptr unsafe.Pointer) bool {
@ -315,7 +315,7 @@ func (encoder *mapInterfaceEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *mapInterfaceEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (encoder *mapInterfaceEncoder) isEmpty(ptr unsafe.Pointer) bool {

View File

@ -53,7 +53,7 @@ func (encoder *sliceEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *sliceEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (encoder *sliceEncoder) isEmpty(ptr unsafe.Pointer) bool {

View File

@ -12,11 +12,12 @@ func (codec *stringCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
}
func (codec *stringCodec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteString(*((*string)(ptr)))
str := *((*string)(ptr))
stream.WriteString(str)
}
func (encoder *stringCodec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *stringCodec) isEmpty(ptr unsafe.Pointer) bool {
@ -35,7 +36,7 @@ func (codec *intCodec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *intCodec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *intCodec) isEmpty(ptr unsafe.Pointer) bool {
@ -54,7 +55,7 @@ func (codec *int8Codec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *int8Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *int8Codec) isEmpty(ptr unsafe.Pointer) bool {
@ -73,7 +74,7 @@ func (codec *int16Codec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *int16Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *int16Codec) isEmpty(ptr unsafe.Pointer) bool {
@ -92,7 +93,7 @@ func (codec *int32Codec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *int32Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *int32Codec) isEmpty(ptr unsafe.Pointer) bool {
@ -111,7 +112,7 @@ func (codec *int64Codec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *int64Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *int64Codec) isEmpty(ptr unsafe.Pointer) bool {
@ -130,7 +131,7 @@ func (codec *uintCodec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *uintCodec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *uintCodec) isEmpty(ptr unsafe.Pointer) bool {
@ -149,7 +150,7 @@ func (codec *uint8Codec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *uint8Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *uint8Codec) isEmpty(ptr unsafe.Pointer) bool {
@ -168,7 +169,7 @@ func (codec *uint16Codec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *uint16Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *uint16Codec) isEmpty(ptr unsafe.Pointer) bool {
@ -187,7 +188,7 @@ func (codec *uint32Codec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *uint32Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *uint32Codec) isEmpty(ptr unsafe.Pointer) bool {
@ -206,7 +207,7 @@ func (codec *uint64Codec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *uint64Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *uint64Codec) isEmpty(ptr unsafe.Pointer) bool {
@ -225,7 +226,7 @@ func (codec *float32Codec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *float32Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *float32Codec) isEmpty(ptr unsafe.Pointer) bool {
@ -244,7 +245,7 @@ func (codec *float64Codec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *float64Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *float64Codec) isEmpty(ptr unsafe.Pointer) bool {
@ -263,7 +264,7 @@ func (codec *boolCodec) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *boolCodec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (codec *boolCodec) isEmpty(ptr unsafe.Pointer) bool {

View File

@ -8,7 +8,6 @@ import (
"strings"
)
func encoderOfStruct(typ reflect.Type) (Encoder, error) {
structEncoder_ := &structEncoder{}
for i := 0; i < typ.NumField(); i++ {
@ -47,14 +46,9 @@ func encoderOfStruct(typ reflect.Type) (Encoder, error) {
return prefix(fmt.Sprintf("{%s}", field.Name)).addToEncoder(encoder, err)
}
// map is stored as pointer in the struct
// but if struct only has one map, it is inlined
if field.Type.Kind() == reflect.Map && typ.NumField() > 1 {
if field.Type.Kind() == reflect.Map {
encoder = &optionalEncoder{encoder}
}
// one field pointer field will be inlined
if field.Type.Kind() == reflect.Ptr && typ.NumField() == 1 {
encoder = (encoder.(*optionalEncoder)).valueEncoder
}
}
for _, fieldName := range fieldNames {
structEncoder_.fields = append(structEncoder_.fields,
@ -1045,7 +1039,7 @@ func (encoder *structFieldEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *structFieldEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (encoder *structFieldEncoder) isEmpty(ptr unsafe.Pointer) bool {
@ -1053,7 +1047,6 @@ func (encoder *structFieldEncoder) isEmpty(ptr unsafe.Pointer) bool {
return encoder.fieldEncoder.isEmpty(unsafe.Pointer(fieldPtr))
}
type structEncoder struct {
fields []*structFieldEncoder
}
@ -1075,7 +1068,24 @@ func (encoder *structEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *structEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
var encoderToUse Encoder
encoderToUse = encoder
if len(encoder.fields) == 1 {
firstEncoder := encoder.fields[0].fieldEncoder
firstEncoderName := reflect.TypeOf(firstEncoder).String()
// interface{} has inline optimization for this case
if firstEncoderName == "*jsoniter.optionalEncoder" {
encoderToUse = &structEncoder{
fields: []*structFieldEncoder{{
field: encoder.fields[0].field,
fieldName: encoder.fields[0].fieldName,
fieldEncoder: firstEncoder.(*optionalEncoder).valueEncoder,
omitempty: encoder.fields[0].omitempty,
}},
}
}
}
writeToStream(val, stream, encoderToUse)
}
func (encoder *structEncoder) isEmpty(ptr unsafe.Pointer) bool {
@ -1087,7 +1097,6 @@ func (encoder *structEncoder) isEmpty(ptr unsafe.Pointer) bool {
return true
}
type emptyStructEncoder struct {
}
@ -1096,7 +1105,7 @@ func (encoder *emptyStructEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *emptyStructEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
writeToStream(val, stream, encoder)
}
func (encoder *emptyStructEncoder) isEmpty(ptr unsafe.Pointer) bool {

View File

@ -4,8 +4,6 @@ import (
"fmt"
"testing"
"github.com/json-iterator/go/require"
"unsafe"
"strconv"
)
func Test_bind_api_demo(t *testing.T) {
@ -24,38 +22,3 @@ func Test_iterator_api_demo(t *testing.T) {
}
fmt.Println(total)
}
type DocumentMatch struct {
Index string `json:"index,omitempty"`
ID string `json:"id"`
Score float64 `json:"score"`
Sort []string `json:"sort,omitempty"`
}
type DocumentMatchCollection []*DocumentMatch
type SearchResult struct {
Hits DocumentMatchCollection `json:"hits"`
}
func Test2(t *testing.T) {
RegisterTypeEncoder("float64", func(ptr unsafe.Pointer, stream *Stream) {
t := *((*float64)(ptr))
stream.WriteRaw(strconv.FormatFloat(t, 'E', -1, 64))
})
hits := []byte(`{"hits":[{"index":"geo","id":"firehouse_grill_brewery","score":3.584608106366055e-07,
"sort":[" \u0001@\t\u0007\u0013;a\u001b}W"]},
{"index":"geo","id":"jack_s_brewing","score":2.3332790568885077e-07,
"sort":[" \u0001@\u0013{w?.\"0\u0010"]},
{"index":"geo","id":"brewpub_on_the_green","score":2.3332790568885077e-07,
"sort":[" \u0001@\u0014\u0017+\u00137QZG"]}]}`)
var h SearchResult
err := Unmarshal(hits, &h)
fmt.Printf("SR %+v \n", h.Hits[0])
b, err := Marshal(h.Hits[0])
if err != nil {
fmt.Printf("error marshalling search res: %v", err)
//return
}
fmt.Printf("SR %s \n", string(b))
}

View File

@ -203,15 +203,23 @@ func Test_recursive_struct(t *testing.T) {
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{}
obj := TestObject{&AnotherObject{&YetAnotherObject{&YetYetAnotherObject{"abc"}}}}
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Me":{}}`, str)
err = UnmarshalFromString(str, &obj)
should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
str, err = MarshalToString(&obj)
should.Nil(err)
should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
}