Tao Wen vor 9 Jahren
Ursprung
Commit
5af8cc4b09
5 geänderte Dateien mit 621 neuen und 631 gelöschten Zeilen
  1. 58 484
      feature_reflect.go
  2. 104 0
      feature_reflect_array.go
  3. 338 0
      feature_reflect_object.go
  4. 112 0
      jsoniter_reflect_struct_test.go
  5. 9 147
      jsoniter_reflect_test.go

+ 58 - 484
feature_reflect.go

@@ -6,7 +6,6 @@ import (
 	"io"
 	"reflect"
 	"strconv"
-	"strings"
 	"sync/atomic"
 	"unsafe"
 )
@@ -25,359 +24,30 @@ type Decoder interface {
 	decode(ptr unsafe.Pointer, iter *Iterator)
 }
 
-type optionalDecoder struct {
-	valueType    reflect.Type
-	valueDecoder Decoder
-}
-
-func (decoder *optionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	if iter.ReadNil() {
-		*((*unsafe.Pointer)(ptr)) = nil
-	} else {
-		if *((*unsafe.Pointer)(ptr)) == nil {
-			// pointer to null, we have to allocate memory to hold the value
-			value := reflect.New(decoder.valueType)
-			decoder.valueDecoder.decode(unsafe.Pointer(value.Pointer()), iter)
-			*((*uintptr)(ptr)) = value.Pointer()
-		} else {
-			// reuse existing instance
-			decoder.valueDecoder.decode(*((*unsafe.Pointer)(ptr)), iter)
-		}
-	}
-}
-
-type generalStructDecoder struct {
-	typ    reflect.Type
-	fields map[string]*structFieldDecoder
-}
-
-func (decoder *generalStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	if !iter.readObjectStart() {
-		return
-	}
-	field := iter.readObjectField()
-	fieldDecoder := decoder.fields[field]
-	if fieldDecoder == nil {
-		iter.Skip()
-	} else {
-		fieldDecoder.decode(ptr, iter)
-	}
-	for iter.nextToken() == ',' {
-		field = iter.readObjectField()
-		fieldDecoder = decoder.fields[field]
-		if fieldDecoder == nil {
-			iter.Skip()
-		} else {
-			fieldDecoder.decode(ptr, iter)
-		}
-	}
-	if iter.Error != nil && iter.Error != io.EOF {
-		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
-	}
-}
-
-type skipDecoder struct {
-	typ 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.typ, iter.Error.Error())
-	}
-}
-
-type oneFieldStructDecoder struct {
-	typ          reflect.Type
-	fieldName    string
-	fieldDecoder *structFieldDecoder
-}
-
-func (decoder *oneFieldStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	if !iter.readObjectStart() {
-		return
-	}
-	field := iter.readObjectField()
-	if field == decoder.fieldName {
-		decoder.fieldDecoder.decode(ptr, iter)
-	} else {
-		iter.Skip()
-	}
-	for iter.nextToken() == ',' {
-		field = iter.readObjectField()
-		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.typ, iter.Error.Error())
-	}
-}
-
-type twoFieldsStructDecoder struct {
-	typ           reflect.Type
-	fieldName1    string
-	fieldDecoder1 *structFieldDecoder
-	fieldName2    string
-	fieldDecoder2 *structFieldDecoder
-}
-
-func (decoder *twoFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	if !iter.readObjectStart() {
-		return
-	}
-	field := iter.readObjectField()
-	switch field {
-	case decoder.fieldName1:
-		decoder.fieldDecoder1.decode(ptr, iter)
-	case decoder.fieldName2:
-		decoder.fieldDecoder2.decode(ptr, iter)
-	default:
-		iter.Skip()
-	}
-	for iter.nextToken() == ',' {
-		field = iter.readObjectField()
-		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.typ, iter.Error.Error())
-	}
-}
-
-type threeFieldsStructDecoder struct {
-	typ           reflect.Type
-	fieldName1    string
-	fieldDecoder1 *structFieldDecoder
-	fieldName2    string
-	fieldDecoder2 *structFieldDecoder
-	fieldName3    string
-	fieldDecoder3 *structFieldDecoder
-}
-
-func (decoder *threeFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	if !iter.readObjectStart() {
-		return
-	}
-	field := iter.readObjectField()
-	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()
-	}
-	for iter.nextToken() == ',' {
-		field = iter.readObjectField()
-		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.typ, iter.Error.Error())
-	}
-}
-
-type fourFieldsStructDecoder struct {
-	typ           reflect.Type
-	fieldName1    string
-	fieldDecoder1 *structFieldDecoder
-	fieldName2    string
-	fieldDecoder2 *structFieldDecoder
-	fieldName3    string
-	fieldDecoder3 *structFieldDecoder
-	fieldName4    string
-	fieldDecoder4 *structFieldDecoder
-}
-
-func (decoder *fourFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	if !iter.readObjectStart() {
-		return
-	}
-	field := iter.readObjectField()
-	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()
-	}
-	for iter.nextToken() == ',' {
-		field = iter.readObjectField()
-		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.typ, iter.Error.Error())
-	}
-}
-
-type structFieldDecoder struct {
-	field        *reflect.StructField
-	fieldDecoder Decoder
-}
-
-func (decoder *structFieldDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	fieldPtr := uintptr(ptr) + decoder.field.Offset
-	decoder.fieldDecoder.decode(unsafe.Pointer(fieldPtr), iter)
-	if iter.Error != nil && iter.Error != io.EOF {
-		iter.Error = fmt.Errorf("%s: %s", decoder.field.Name, iter.Error.Error())
-	}
-}
-
-type mapDecoder struct {
-	mapType      reflect.Type
-	elemType     reflect.Type
-	elemDecoder  Decoder
-	mapInterface emptyInterface
-}
-
-func (decoder *mapDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	// dark magic to cast unsafe.Pointer back to interface{} using reflect.Type
-	mapInterface := decoder.mapInterface
-	mapInterface.word = ptr
-	realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
-	realVal := reflect.ValueOf(*realInterface).Elem()
-
-	for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
-		elem := reflect.New(decoder.elemType)
-		decoder.elemDecoder.decode(unsafe.Pointer(elem.Pointer()), iter)
-		// to put into map, we have to use reflection
-		realVal.SetMapIndex(reflect.ValueOf(string([]byte(field))), elem.Elem())
-	}
-}
-
-type sliceDecoder struct {
-	sliceType   reflect.Type
-	elemType    reflect.Type
-	elemDecoder Decoder
-}
+type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
+type ExtensionFunc func(typ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc)
 
-// sliceHeader is a safe version of SliceHeader used within this package.
-type sliceHeader struct {
-	Data unsafe.Pointer
-	Len  int
-	Cap  int
+type funcDecoder struct {
+	fun DecoderFunc
 }
 
-func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	decoder.doDecode(ptr, iter)
-	if iter.Error != nil && iter.Error != io.EOF {
-		iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
-	}
+func (decoder *funcDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	decoder.fun(ptr, iter)
 }
 
-func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
-	slice := (*sliceHeader)(ptr)
-	reuseSlice(slice, decoder.sliceType, 4)
-	if !iter.ReadArray() {
-		return
-	}
-	offset := uintptr(0)
-	decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
-	if !iter.ReadArray() {
-		slice.Len = 1
-		return
-	}
-	offset += decoder.elemType.Size()
-	decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
-	if !iter.ReadArray() {
-		slice.Len = 2
-		return
-	}
-	offset += decoder.elemType.Size()
-	decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
-	if !iter.ReadArray() {
-		slice.Len = 3
-		return
-	}
-	offset += decoder.elemType.Size()
-	decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
-	slice.Len = 4
-	for iter.ReadArray() {
-		growOne(slice, decoder.sliceType, decoder.elemType)
-		offset += decoder.elemType.Size()
-		decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
-	}
-}
+var DECODERS unsafe.Pointer
 
-// grow grows the slice s so that it can hold extra more values, allocating
-// more capacity if needed. It also returns the old and new slice lengths.
-func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
-	newLen := slice.Len + 1
-	if newLen <= slice.Cap {
-		slice.Len = newLen
-		return
-	}
-	newCap := slice.Cap
-	if newCap == 0 {
-		newCap = 1
-	} else {
-		for newCap < newLen {
-			if slice.Len < 1024 {
-				newCap += newCap
-			} else {
-				newCap += newCap / 4
-			}
-		}
-	}
-	dst := unsafe.Pointer(reflect.MakeSlice(sliceType, newLen, newCap).Pointer())
-	// copy old array into new array
-	originalBytesCount := uintptr(slice.Len) * elementType.Size()
-	srcPtr := (*[1 << 30]byte)(slice.Data)
-	dstPtr := (*[1 << 30]byte)(dst)
-	for i := uintptr(0); i < originalBytesCount; i++ {
-		dstPtr[i] = srcPtr[i]
-	}
-	slice.Len = newLen
-	slice.Cap = newCap
-	slice.Data = dst
-}
+var typeDecoders map[string]Decoder
+var fieldDecoders map[string]Decoder
+var extensions []ExtensionFunc
 
-func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
-	if expectedCap <= slice.Cap {
-		return
-	}
-	dst := unsafe.Pointer(reflect.MakeSlice(sliceType, 0, expectedCap).Pointer())
-	slice.Cap = expectedCap
-	slice.Data = dst
+func init() {
+	typeDecoders = map[string]Decoder{}
+	fieldDecoders = map[string]Decoder{}
+	extensions = []ExtensionFunc{}
+	atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
 }
 
-var DECODERS unsafe.Pointer
-
 func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
 	retry := true
 	for retry {
@@ -398,28 +68,6 @@ func getDecoderFromCache(cacheKey reflect.Type) Decoder {
 	return cache[cacheKey]
 }
 
-var typeDecoders map[string]Decoder
-var fieldDecoders map[string]Decoder
-var extensions []ExtensionFunc
-
-func init() {
-	typeDecoders = map[string]Decoder{}
-	fieldDecoders = map[string]Decoder{}
-	extensions = []ExtensionFunc{}
-	atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
-}
-
-type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
-type ExtensionFunc func(typ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc)
-
-type funcDecoder struct {
-	fun DecoderFunc
-}
-
-func (decoder *funcDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	decoder.fun(ptr, iter)
-}
-
 // RegisterTypeDecoder can register a type for json object
 func RegisterTypeDecoder(typ string, fun DecoderFunc) {
 	typeDecoders[typ] = &funcDecoder{fun}
@@ -441,6 +89,49 @@ func CleanDecoders() {
 	fieldDecoders = map[string]Decoder{}
 }
 
+type optionalDecoder struct {
+	valueType    reflect.Type
+	valueDecoder Decoder
+}
+
+func (decoder *optionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	if iter.ReadNil() {
+		*((*unsafe.Pointer)(ptr)) = nil
+	} else {
+		if *((*unsafe.Pointer)(ptr)) == nil {
+			// pointer to null, we have to allocate memory to hold the value
+			value := reflect.New(decoder.valueType)
+			decoder.valueDecoder.decode(unsafe.Pointer(value.Pointer()), iter)
+			*((*uintptr)(ptr)) = value.Pointer()
+		} else {
+			// reuse existing instance
+			decoder.valueDecoder.decode(*((*unsafe.Pointer)(ptr)), iter)
+		}
+	}
+}
+
+type mapDecoder struct {
+	mapType      reflect.Type
+	elemType     reflect.Type
+	elemDecoder  Decoder
+	mapInterface emptyInterface
+}
+
+func (decoder *mapDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	// dark magic to cast unsafe.Pointer back to interface{} using reflect.Type
+	mapInterface := decoder.mapInterface
+	mapInterface.word = ptr
+	realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
+	realVal := reflect.ValueOf(*realInterface).Elem()
+
+	for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
+		elem := reflect.New(decoder.elemType)
+		decoder.elemDecoder.decode(unsafe.Pointer(elem.Pointer()), iter)
+		// to put into map, we have to use reflection
+		realVal.SetMapIndex(reflect.ValueOf(string([]byte(field))), elem.Elem())
+	}
+}
+
 // emptyInterface is the header for an interface{} value.
 type emptyInterface struct {
 	typ  *struct{}
@@ -646,123 +337,6 @@ func decoderOfOptional(typ reflect.Type) (Decoder, error) {
 	return &optionalDecoder{typ, decoder}, nil
 }
 
-func decoderOfStruct(typ reflect.Type) (Decoder, error) {
-	fields := map[string]*structFieldDecoder{}
-	for i := 0; i < typ.NumField(); i++ {
-		field := typ.Field(i)
-		fieldDecoderKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
-		var fieldNames []string
-		for _, extension := range extensions {
-			alternativeFieldNames, fun := extension(typ, &field)
-			if alternativeFieldNames != nil {
-				fieldNames = alternativeFieldNames
-			}
-			if fun != nil {
-				fieldDecoders[fieldDecoderKey] = &funcDecoder{fun}
-			}
-		}
-		decoder := fieldDecoders[fieldDecoderKey]
-		tagParts := strings.Split(field.Tag.Get("json"), ",")
-		// if fieldNames set by extension, use theirs, otherwise try tags
-		if fieldNames == nil {
-			/// tagParts[0] always present, even if no tags
-			switch tagParts[0] {
-			case "":
-				fieldNames = []string{field.Name}
-			case "-":
-				fieldNames = []string{}
-			default:
-				fieldNames = []string{tagParts[0]}
-			}
-		}
-		if decoder == nil {
-			var err error
-			decoder, err = decoderOfPtr(field.Type)
-			if err != nil {
-				return prefix(fmt.Sprintf("{%s}", field.Name)).addTo(decoder, err)
-			}
-		}
-		if len(tagParts) > 1 && tagParts[1] == "string" {
-			decoder = &stringNumberDecoder{decoder}
-		}
-		for _, fieldName := range fieldNames {
-			fields[fieldName] = &structFieldDecoder{&field, decoder}
-		}
-	}
-	switch len(fields) {
-	case 0:
-		return &skipDecoder{typ}, nil
-	case 1:
-		for fieldName, fieldDecoder := range fields {
-			return &oneFieldStructDecoder{typ, fieldName, fieldDecoder}, nil
-		}
-	case 2:
-		var fieldName1 string
-		var fieldName2 string
-		var fieldDecoder1 *structFieldDecoder
-		var fieldDecoder2 *structFieldDecoder
-		for fieldName, fieldDecoder := range fields {
-			if fieldName1 == "" {
-				fieldName1 = fieldName
-				fieldDecoder1 = fieldDecoder
-			} else {
-				fieldName2 = fieldName
-				fieldDecoder2 = fieldDecoder
-			}
-		}
-		return &twoFieldsStructDecoder{typ, fieldName1, fieldDecoder1, fieldName2, fieldDecoder2}, nil
-	case 3:
-		var fieldName1 string
-		var fieldName2 string
-		var fieldName3 string
-		var fieldDecoder1 *structFieldDecoder
-		var fieldDecoder2 *structFieldDecoder
-		var fieldDecoder3 *structFieldDecoder
-		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{typ,
-			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
-	case 4:
-		var fieldName1 string
-		var fieldName2 string
-		var fieldName3 string
-		var fieldName4 string
-		var fieldDecoder1 *structFieldDecoder
-		var fieldDecoder2 *structFieldDecoder
-		var fieldDecoder3 *structFieldDecoder
-		var fieldDecoder4 *structFieldDecoder
-		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{typ,
-			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
-			fieldName4, fieldDecoder4}, nil
-	}
-	return &generalStructDecoder{typ, fields}, nil
-}
-
 func decoderOfSlice(typ reflect.Type) (Decoder, error) {
 	decoder, err := decoderOfPtr(typ.Elem())
 	if err != nil {

+ 104 - 0
feature_reflect_array.go

@@ -0,0 +1,104 @@
+package jsoniter
+
+import (
+	"unsafe"
+	"reflect"
+	"io"
+	"fmt"
+)
+
+type sliceDecoder struct {
+	sliceType   reflect.Type
+	elemType    reflect.Type
+	elemDecoder Decoder
+}
+
+// sliceHeader is a safe version of SliceHeader used within this package.
+type sliceHeader struct {
+	Data unsafe.Pointer
+	Len  int
+	Cap  int
+}
+
+func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	decoder.doDecode(ptr, iter)
+	if iter.Error != nil && iter.Error != io.EOF {
+		iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
+	}
+}
+
+func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
+	slice := (*sliceHeader)(ptr)
+	reuseSlice(slice, decoder.sliceType, 4)
+	if !iter.ReadArray() {
+		return
+	}
+	offset := uintptr(0)
+	decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
+	if !iter.ReadArray() {
+		slice.Len = 1
+		return
+	}
+	offset += decoder.elemType.Size()
+	decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
+	if !iter.ReadArray() {
+		slice.Len = 2
+		return
+	}
+	offset += decoder.elemType.Size()
+	decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
+	if !iter.ReadArray() {
+		slice.Len = 3
+		return
+	}
+	offset += decoder.elemType.Size()
+	decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
+	slice.Len = 4
+	for iter.ReadArray() {
+		growOne(slice, decoder.sliceType, decoder.elemType)
+		offset += decoder.elemType.Size()
+		decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
+	}
+}
+
+// grow grows the slice s so that it can hold extra more values, allocating
+// more capacity if needed. It also returns the old and new slice lengths.
+func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
+	newLen := slice.Len + 1
+	if newLen <= slice.Cap {
+		slice.Len = newLen
+		return
+	}
+	newCap := slice.Cap
+	if newCap == 0 {
+		newCap = 1
+	} else {
+		for newCap < newLen {
+			if slice.Len < 1024 {
+				newCap += newCap
+			} else {
+				newCap += newCap / 4
+			}
+		}
+	}
+	dst := unsafe.Pointer(reflect.MakeSlice(sliceType, newLen, newCap).Pointer())
+	// copy old array into new array
+	originalBytesCount := uintptr(slice.Len) * elementType.Size()
+	srcPtr := (*[1 << 30]byte)(slice.Data)
+	dstPtr := (*[1 << 30]byte)(dst)
+	for i := uintptr(0); i < originalBytesCount; i++ {
+		dstPtr[i] = srcPtr[i]
+	}
+	slice.Len = newLen
+	slice.Cap = newCap
+	slice.Data = dst
+}
+
+func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
+	if expectedCap <= slice.Cap {
+		return
+	}
+	dst := unsafe.Pointer(reflect.MakeSlice(sliceType, 0, expectedCap).Pointer())
+	slice.Cap = expectedCap
+	slice.Data = dst
+}

+ 338 - 0
feature_reflect_object.go

@@ -0,0 +1,338 @@
+package jsoniter
+
+import (
+	"io"
+	"fmt"
+	"reflect"
+	"unsafe"
+	"strings"
+)
+
+func decoderOfStruct(typ reflect.Type) (Decoder, error) {
+	fields := map[string]*structFieldDecoder{}
+	for i := 0; i < typ.NumField(); i++ {
+		field := typ.Field(i)
+		fieldDecoderKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
+		var fieldNames []string
+		for _, extension := range extensions {
+			alternativeFieldNames, fun := extension(typ, &field)
+			if alternativeFieldNames != nil {
+				fieldNames = alternativeFieldNames
+			}
+			if fun != nil {
+				fieldDecoders[fieldDecoderKey] = &funcDecoder{fun}
+			}
+		}
+		decoder := fieldDecoders[fieldDecoderKey]
+		tagParts := strings.Split(field.Tag.Get("json"), ",")
+		// if fieldNames set by extension, use theirs, otherwise try tags
+		if fieldNames == nil {
+			/// tagParts[0] always present, even if no tags
+			switch tagParts[0] {
+			case "":
+				fieldNames = []string{field.Name}
+			case "-":
+				fieldNames = []string{}
+			default:
+				fieldNames = []string{tagParts[0]}
+			}
+		}
+		if decoder == nil {
+			var err error
+			decoder, err = decoderOfPtr(field.Type)
+			if err != nil {
+				return prefix(fmt.Sprintf("{%s}", field.Name)).addTo(decoder, err)
+			}
+		}
+		if len(tagParts) > 1 && tagParts[1] == "string" {
+			decoder = &stringNumberDecoder{decoder}
+		}
+		for _, fieldName := range fieldNames {
+			fields[fieldName] = &structFieldDecoder{&field, decoder}
+		}
+	}
+	switch len(fields) {
+	case 0:
+		return &skipDecoder{typ}, nil
+	case 1:
+		for fieldName, fieldDecoder := range fields {
+			return &oneFieldStructDecoder{typ, fieldName, fieldDecoder}, nil
+		}
+	case 2:
+		var fieldName1 string
+		var fieldName2 string
+		var fieldDecoder1 *structFieldDecoder
+		var fieldDecoder2 *structFieldDecoder
+		for fieldName, fieldDecoder := range fields {
+			if fieldName1 == "" {
+				fieldName1 = fieldName
+				fieldDecoder1 = fieldDecoder
+			} else {
+				fieldName2 = fieldName
+				fieldDecoder2 = fieldDecoder
+			}
+		}
+		return &twoFieldsStructDecoder{typ, fieldName1, fieldDecoder1, fieldName2, fieldDecoder2}, nil
+	case 3:
+		var fieldName1 string
+		var fieldName2 string
+		var fieldName3 string
+		var fieldDecoder1 *structFieldDecoder
+		var fieldDecoder2 *structFieldDecoder
+		var fieldDecoder3 *structFieldDecoder
+		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{typ,
+			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
+	case 4:
+		var fieldName1 string
+		var fieldName2 string
+		var fieldName3 string
+		var fieldName4 string
+		var fieldDecoder1 *structFieldDecoder
+		var fieldDecoder2 *structFieldDecoder
+		var fieldDecoder3 *structFieldDecoder
+		var fieldDecoder4 *structFieldDecoder
+		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{typ,
+			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
+			fieldName4, fieldDecoder4}, nil
+	}
+	return &generalStructDecoder{typ, fields}, nil
+}
+
+type generalStructDecoder struct {
+	typ    reflect.Type
+	fields map[string]*structFieldDecoder
+}
+
+func (decoder *generalStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	if !iter.readObjectStart() {
+		return
+	}
+	field := iter.readObjectField()
+	fieldDecoder := decoder.fields[field]
+	if fieldDecoder == nil {
+		iter.Skip()
+	} else {
+		fieldDecoder.decode(ptr, iter)
+	}
+	for iter.nextToken() == ',' {
+		field = iter.readObjectField()
+		fieldDecoder = decoder.fields[field]
+		if fieldDecoder == nil {
+			iter.Skip()
+		} else {
+			fieldDecoder.decode(ptr, iter)
+		}
+	}
+	if iter.Error != nil && iter.Error != io.EOF {
+		iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
+	}
+}
+
+type skipDecoder struct {
+	typ 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.typ, iter.Error.Error())
+	}
+}
+
+type oneFieldStructDecoder struct {
+	typ          reflect.Type
+	fieldName    string
+	fieldDecoder *structFieldDecoder
+}
+
+func (decoder *oneFieldStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	if !iter.readObjectStart() {
+		return
+	}
+	field := iter.readObjectField()
+	if field == decoder.fieldName {
+		decoder.fieldDecoder.decode(ptr, iter)
+	} else {
+		iter.Skip()
+	}
+	for iter.nextToken() == ',' {
+		field = iter.readObjectField()
+		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.typ, iter.Error.Error())
+	}
+}
+
+type twoFieldsStructDecoder struct {
+	typ           reflect.Type
+	fieldName1    string
+	fieldDecoder1 *structFieldDecoder
+	fieldName2    string
+	fieldDecoder2 *structFieldDecoder
+}
+
+func (decoder *twoFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	if !iter.readObjectStart() {
+		return
+	}
+	field := iter.readObjectField()
+	switch field {
+	case decoder.fieldName1:
+		decoder.fieldDecoder1.decode(ptr, iter)
+	case decoder.fieldName2:
+		decoder.fieldDecoder2.decode(ptr, iter)
+	default:
+		iter.Skip()
+	}
+	for iter.nextToken() == ',' {
+		field = iter.readObjectField()
+		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.typ, iter.Error.Error())
+	}
+}
+
+type threeFieldsStructDecoder struct {
+	typ           reflect.Type
+	fieldName1    string
+	fieldDecoder1 *structFieldDecoder
+	fieldName2    string
+	fieldDecoder2 *structFieldDecoder
+	fieldName3    string
+	fieldDecoder3 *structFieldDecoder
+}
+
+func (decoder *threeFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	if !iter.readObjectStart() {
+		return
+	}
+	field := iter.readObjectField()
+	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()
+	}
+	for iter.nextToken() == ',' {
+		field = iter.readObjectField()
+		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.typ, iter.Error.Error())
+	}
+}
+
+type fourFieldsStructDecoder struct {
+	typ           reflect.Type
+	fieldName1    string
+	fieldDecoder1 *structFieldDecoder
+	fieldName2    string
+	fieldDecoder2 *structFieldDecoder
+	fieldName3    string
+	fieldDecoder3 *structFieldDecoder
+	fieldName4    string
+	fieldDecoder4 *structFieldDecoder
+}
+
+func (decoder *fourFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	if !iter.readObjectStart() {
+		return
+	}
+	field := iter.readObjectField()
+	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()
+	}
+	for iter.nextToken() == ',' {
+		field = iter.readObjectField()
+		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.typ, iter.Error.Error())
+	}
+}
+
+type structFieldDecoder struct {
+	field        *reflect.StructField
+	fieldDecoder Decoder
+}
+
+func (decoder *structFieldDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	fieldPtr := uintptr(ptr) + decoder.field.Offset
+	decoder.fieldDecoder.decode(unsafe.Pointer(fieldPtr), iter)
+	if iter.Error != nil && iter.Error != io.EOF {
+		iter.Error = fmt.Errorf("%s: %s", decoder.field.Name, iter.Error.Error())
+	}
+}

+ 112 - 0
jsoniter_reflect_struct_test.go

@@ -0,0 +1,112 @@
+package jsoniter
+
+import (
+	"testing"
+	"github.com/json-iterator/go/require"
+)
+
+func Test_decode_one_field_struct(t *testing.T) {
+	should := require.New(t)
+	type TestObject struct {
+		field1 string
+	}
+	obj := TestObject{}
+	should.Nil(UnmarshalString(`{}`, &obj))
+	should.Equal("", obj.field1)
+	should.Nil(UnmarshalString(`{"field1": "hello"}`, &obj))
+	should.Equal("hello", obj.field1)
+}
+
+func Test_decode_two_fields_struct(t *testing.T) {
+	should := require.New(t)
+	type TestObject struct {
+		field1 string
+		field2 string
+	}
+	obj := TestObject{}
+	should.Nil(UnmarshalString(`{}`, &obj))
+	should.Equal("", obj.field1)
+	should.Nil(UnmarshalString(`{"field1": "a", "field2": "b"}`, &obj))
+	should.Equal("a", obj.field1)
+	should.Equal("b", obj.field2)
+}
+
+func Test_decode_three_fields_struct(t *testing.T) {
+	should := require.New(t)
+	type TestObject struct {
+		field1 string
+		field2 string
+		field3 string
+	}
+	obj := TestObject{}
+	should.Nil(UnmarshalString(`{}`, &obj))
+	should.Equal("", obj.field1)
+	should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c"}`, &obj))
+	should.Equal("a", obj.field1)
+	should.Equal("b", obj.field2)
+	should.Equal("c", obj.field3)
+}
+
+func Test_decode_four_fields_struct(t *testing.T) {
+	should := require.New(t)
+	type TestObject struct {
+		field1 string
+		field2 string
+		field3 string
+		field4 string
+	}
+	obj := TestObject{}
+	should.Nil(UnmarshalString(`{}`, &obj))
+	should.Equal("", obj.field1)
+	should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d"}`, &obj))
+	should.Equal("a", obj.field1)
+	should.Equal("b", obj.field2)
+	should.Equal("c", obj.field3)
+	should.Equal("d", obj.field4)
+}
+
+func Test_decode_five_fields_struct(t *testing.T) {
+	should := require.New(t)
+	type TestObject struct {
+		field1 string
+		field2 string
+		field3 string
+		field4 string
+		field5 string
+	}
+	obj := TestObject{}
+	should.Nil(UnmarshalString(`{}`, &obj))
+	should.Equal("", obj.field1)
+	should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d", "field5": "e"}`, &obj))
+	should.Equal("a", obj.field1)
+	should.Equal("b", obj.field2)
+	should.Equal("c", obj.field3)
+	should.Equal("d", obj.field4)
+	should.Equal("e", obj.field5)
+}
+
+func Test_decode_struct_with_optional_field(t *testing.T) {
+	should := require.New(t)
+	type TestObject struct {
+		field1 *string
+		field2 *string
+	}
+	obj := TestObject{}
+	UnmarshalString(`{"field1": null, "field2": "world"}`, &obj)
+	should.Nil(obj.field1)
+	should.Equal("world", *obj.field2)
+}
+
+func Test_decode_struct_field_with_tag(t *testing.T) {
+	should := require.New(t)
+	type TestObject struct {
+		Field1 string `json:"field-1"`
+		Field2 string `json:"-"`
+		Field3 int    `json:",string"`
+	}
+	obj := TestObject{Field2: "world"}
+	UnmarshalString(`{"field-1": "hello", "field2": "", "Field3": "100"}`, &obj)
+	should.Equal("hello", obj.Field1)
+	should.Equal("world", obj.Field2)
+	should.Equal(100, obj.Field3)
+}

+ 9 - 147
jsoniter_reflect_test.go

@@ -8,159 +8,21 @@ import (
 	"github.com/json-iterator/go/require"
 )
 
-func Test_reflect_one_field_struct(t *testing.T) {
+func Test_decode_slice(t *testing.T) {
 	should := require.New(t)
-	type TestObject struct {
-		field1 string
-	}
-	obj := TestObject{}
-	should.Nil(UnmarshalString(`{}`, &obj))
-	should.Equal("", obj.field1)
-	should.Nil(UnmarshalString(`{"field1": "hello"}`, &obj))
-	should.Equal("hello", obj.field1)
-}
-
-func Test_reflect_two_fields_struct(t *testing.T) {
-	should := require.New(t)
-	type TestObject struct {
-		field1 string
-		field2 string
-	}
-	obj := TestObject{}
-	should.Nil(UnmarshalString(`{}`, &obj))
-	should.Equal("", obj.field1)
-	should.Nil(UnmarshalString(`{"field1": "a", "field2": "b"}`, &obj))
-	should.Equal("a", obj.field1)
-	should.Equal("b", obj.field2)
-}
-
-func Test_reflect_three_fields_struct(t *testing.T) {
-	should := require.New(t)
-	type TestObject struct {
-		field1 string
-		field2 string
-		field3 string
-	}
-	obj := TestObject{}
-	should.Nil(UnmarshalString(`{}`, &obj))
-	should.Equal("", obj.field1)
-	should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c"}`, &obj))
-	should.Equal("a", obj.field1)
-	should.Equal("b", obj.field2)
-	should.Equal("c", obj.field3)
-}
-
-func Test_reflect_four_fields_struct(t *testing.T) {
-	should := require.New(t)
-	type TestObject struct {
-		field1 string
-		field2 string
-		field3 string
-		field4 string
-	}
-	obj := TestObject{}
-	should.Nil(UnmarshalString(`{}`, &obj))
-	should.Equal("", obj.field1)
-	should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d"}`, &obj))
-	should.Equal("a", obj.field1)
-	should.Equal("b", obj.field2)
-	should.Equal("c", obj.field3)
-	should.Equal("d", obj.field4)
-}
-
-func Test_reflect_five_fields_struct(t *testing.T) {
-	should := require.New(t)
-	type TestObject struct {
-		field1 string
-		field2 string
-		field3 string
-		field4 string
-		field5 string
-	}
-	obj := TestObject{}
-	should.Nil(UnmarshalString(`{}`, &obj))
-	should.Equal("", obj.field1)
-	should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d", "field5": "e"}`, &obj))
-	should.Equal("a", obj.field1)
-	should.Equal("b", obj.field2)
-	should.Equal("c", obj.field3)
-	should.Equal("d", obj.field4)
-	should.Equal("e", obj.field5)
-}
-
-func Test_struct_with_optional_field(t *testing.T) {
-	should := require.New(t)
-	type TestObject struct {
-		field1 *string
-		field2 *string
-	}
-	obj := TestObject{}
-	UnmarshalString(`{"field1": null, "field2": "world"}`, &obj)
-	should.Nil(obj.field1)
-	should.Equal("world", *obj.field2)
-}
-
-type StructOfTag struct {
-	Field1 string `json:"field-1"`
-	Field2 string `json:"-"`
-	Field3 int    `json:",string"`
-}
-
-func Test_reflect_struct_tag_field(t *testing.T) {
-	iter := ParseString(`{"field-1": "hello", "field2": "", "Field3": "100"}`)
-	Struct := StructOfTag{Field2: "world"}
-	iter.Read(&Struct)
-	if Struct.Field1 != "hello" {
-		fmt.Println(iter.Error)
-		t.Fatal(Struct.Field1)
-	}
-	if Struct.Field2 != "world" {
-		fmt.Println(iter.Error)
-		t.Fatal(Struct.Field2)
-	}
-	if Struct.Field3 != 100 {
-		fmt.Println(iter.Error)
-		t.Fatal(Struct.Field3)
-	}
-}
-
-func Test_reflect_slice(t *testing.T) {
-	iter := ParseString(`["hello", "world"]`)
 	slice := make([]string, 0, 5)
-	iter.Read(&slice)
-	if len(slice) != 2 {
-		fmt.Println(iter.Error)
-		t.Fatal(len(slice))
-	}
-	if slice[0] != "hello" {
-		fmt.Println(iter.Error)
-		t.Fatal(slice[0])
-	}
-	if slice[1] != "world" {
-		fmt.Println(iter.Error)
-		t.Fatal(slice[1])
-	}
+	UnmarshalString(`["hello", "world"]`, &slice)
+	should.Equal([]string{"hello", "world"}, slice)
 }
 
-func Test_reflect_large_slice(t *testing.T) {
-	iter := ParseString(`[1,2,3,4,5,6,7,8,9]`)
+func Test_decode_large_slice(t *testing.T) {
+	should := require.New(t)
 	slice := make([]int, 0, 1)
-	iter.Read(&slice)
-	if len(slice) != 9 {
-		fmt.Println(iter.Error)
-		t.Fatal(len(slice))
-	}
-	if slice[0] != 1 {
-		fmt.Println(iter.Error)
-		t.Fatal(slice[0])
-	}
-	if slice[8] != 9 {
-		fmt.Println(iter.Error)
-		t.Fatal(slice[8])
-	}
+	UnmarshalString(`[1,2,3,4,5,6,7,8,9]`, &slice)
+	should.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}, slice)
 }
 
-func Test_reflect_nested(t *testing.T) {
+func Test_decode_nested(t *testing.T) {
 	type StructOfString struct {
 		field1 string
 		field2 string
@@ -186,7 +48,7 @@ func Test_reflect_nested(t *testing.T) {
 	}
 }
 
-func Test_reflect_base64(t *testing.T) {
+func Test_decode_base64(t *testing.T) {
 	iter := ParseString(`"YWJj"`)
 	val := []byte{}
 	RegisterTypeDecoder("[]uint8", func(ptr unsafe.Pointer, iter *Iterator) {