Selaa lähdekoodia

fix read any; reuse existing obj for optional

Tao Wen 9 vuotta sitten
vanhempi
commit
97849e019f
7 muutettua tiedostoa jossa 195 lisäystä ja 153 poistoa
  1. 85 0
      feature_iter_object.go
  2. 43 13
      feature_reflect.go
  3. 34 91
      jsoniter.go
  4. 3 0
      jsoniter_any_test.go
  5. 9 29
      jsoniter_customize_test.go
  6. 15 15
      jsoniter_large_file_test.go
  7. 6 5
      jsoniter_reflect_test.go

+ 85 - 0
feature_iter_object.go

@@ -0,0 +1,85 @@
+package jsoniter
+
+import "unsafe"
+
+func (iter *Iterator) ReadObject() (ret string) {
+	c := iter.nextToken()
+	if iter.Error != nil {
+		return
+	}
+	switch c {
+	case 'n': {
+		iter.skipUntilBreak()
+		if iter.Error != nil {
+			return
+		}
+		return "" // null
+	}
+	case '{': {
+		c = iter.nextToken()
+		if iter.Error != nil {
+			return
+		}
+		switch c {
+		case '}':
+			return "" // end of object
+		case '"':
+			iter.unreadByte()
+			return iter.readObjectField()
+		default:
+			iter.ReportError("ReadObject", `expect " after {`)
+			return
+		}
+	}
+	case ',':
+		return iter.readObjectField()
+	case '}':
+		return "" // end of object
+	default:
+		iter.ReportError("ReadObject", `expect { or , or } or n`)
+		return
+	}
+}
+
+func (iter *Iterator) readObjectStart() bool {
+	c := iter.nextToken()
+	if c == '{' {
+		c = iter.nextToken()
+		if c == '}' {
+			return false
+		}
+		iter.unreadByte()
+		return true
+	}
+	iter.ReportError("readObjectStart", "expect { ")
+	return false
+}
+
+func (iter *Iterator) readObjectField() (ret string) {
+	str := iter.readStringAsBytes()
+	if iter.skipWhitespacesWithoutLoadMore() {
+		if ret == "" {
+			ret = string(str);
+		}
+		if !iter.loadMore() {
+			return
+		}
+	}
+	if iter.buf[iter.head] != ':' {
+		iter.ReportError("ReadObject", "expect : after object field")
+		return
+	}
+	iter.head++
+	if iter.skipWhitespacesWithoutLoadMore() {
+		if ret == "" {
+			ret = string(str);
+		}
+		if !iter.loadMore() {
+			return
+		}
+	}
+	if ret == "" {
+		return *(*string)(unsafe.Pointer(&str))
+	}
+	return ret
+}

+ 43 - 13
feature_reflect.go

@@ -11,6 +11,15 @@ import (
 	"strconv"
 )
 
+/*
+Reflection on type to create decoders, which is then cached
+Reflection on value is avoided as we can, as the reflect.Value itself will allocate, with following exceptions
+1. create instance of new value, for example *int will need a int to be allocated
+2. append to slice, if the existing cap is not enough, allocate will be done using Reflect.New
+3. assignment to map, both key and value will be reflect.Value
+For a simple struct binding, it will be reflect.Value free and allocation free
+ */
+
 type Decoder interface {
 	decode(ptr unsafe.Pointer, iter *Iterator)
 }
@@ -133,7 +142,7 @@ type stringNumberDecoder struct {
 }
 
 func (decoder *stringNumberDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	c := iter.readByte()
+	c := iter.nextToken()
 	if c != '"' {
 		iter.ReportError("stringNumberDecoder", `expect "`)
 		return
@@ -158,9 +167,15 @@ func (decoder *optionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
 	if iter.ReadNull() {
 		*((*unsafe.Pointer)(ptr)) = nil
 	} else {
-		value := reflect.New(decoder.valueType)
-		decoder.valueDecoder.decode(unsafe.Pointer(value.Pointer()), iter)
-		*((*uintptr)(ptr)) = value.Pointer()
+		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)
+		}
 	}
 }
 
@@ -278,7 +293,24 @@ type fourFieldsStructDecoder struct {
 }
 
 func (decoder *fourFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
-	for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
+	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)
@@ -327,6 +359,7 @@ func (decoder *mapDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
 	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())
 	}
 }
@@ -406,6 +439,7 @@ func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Typ
 		}
 	}
 	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)
@@ -554,9 +588,13 @@ func (iter *Iterator) readNumber() (ret *Any) {
 				str = append(str, c)
 				continue
 			default:
+				iter.head = i
 				hasMore = false
 				break
 			}
+			if !hasMore {
+				break
+			}
 		}
 		if hasMore {
 			if !iter.loadMore() {
@@ -632,14 +670,6 @@ func decoderOfPtr(type_ reflect.Type) (Decoder, error) {
 	if typeName == "jsoniter.Any" {
 		return &anyDecoder{}, nil
 	}
-
-	for _, extension := range extensions {
-		alternativeFieldNames, func_ := extension(type_, nil)
-		if alternativeFieldNames != nil {
-			return nil, fmt.Errorf("%v should not return alternative field names when only type is being passed", extension)
-		}
-		typeDecoders[typeName] = &funcDecoder{func_}
-	}
 	typeDecoder := typeDecoders[typeName]
 	if typeDecoder != nil {
 		return typeDecoder, nil

+ 34 - 91
jsoniter.go

@@ -69,24 +69,31 @@ type Iterator struct {
 	Error  error
 }
 
+func Create() *Iterator {
+	return &Iterator{
+		reader: nil,
+		buf: nil,
+		head: 0,
+		tail: 0,
+	}
+}
+
 func Parse(reader io.Reader, bufSize int) *Iterator {
-	iter := &Iterator{
+	return &Iterator{
 		reader: reader,
 		buf: make([]byte, bufSize),
 		head: 0,
 		tail: 0,
 	}
-	return iter
 }
 
 func ParseBytes(input []byte) *Iterator {
-	iter := &Iterator{
+	return &Iterator{
 		reader: nil,
 		buf: input,
 		head: 0,
 		tail: len(input),
 	}
-	return iter
 }
 
 func ParseString(input string) *Iterator {
@@ -101,7 +108,6 @@ func (iter *Iterator) Reset(reader io.Reader) *Iterator {
 }
 
 func (iter *Iterator) ResetBytes(input []byte) *Iterator {
-	// only for benchmarking
 	iter.reader = nil
 	iter.Error = nil
 	iter.buf = input
@@ -111,7 +117,7 @@ func (iter *Iterator) ResetBytes(input []byte) *Iterator {
 }
 
 func (iter *Iterator) WhatIsNext() ValueType {
-	valueType := valueTypes[iter.readByte()];
+	valueType := valueTypes[iter.nextToken()];
 	iter.unreadByte();
 	return valueType;
 }
@@ -261,7 +267,7 @@ func (iter *Iterator) ReadUint32() (ret uint32) {
 }
 
 func (iter *Iterator) ReadUint64() (ret uint64) {
-	c := iter.readByte()
+	c := iter.nextToken()
 	v := digits[c]
 	if v == 0 {
 		return 0 // single zero
@@ -327,7 +333,7 @@ func (iter *Iterator) ReadInt32() (ret int32) {
 }
 
 func (iter *Iterator) ReadInt64() (ret int64) {
-	c := iter.readByte()
+	c := iter.nextToken()
 	if iter.Error != nil {
 		return
 	}
@@ -350,22 +356,27 @@ func (iter *Iterator) ReadString() (ret string) {
 
 func (iter *Iterator) readStringAsBytes() (ret []byte) {
 	c := iter.nextToken()
+	if c == '"' {
+		end := iter.findStringEndWithoutEscape()
+		if end != -1 {
+			// fast path: reuse the underlying buffer
+			ret = iter.buf[iter.head:end-1]
+			iter.head = end
+			return ret
+		}
+		return iter.readStringAsBytesSlowPath()
+	}
 	if c == 'n' {
 		iter.skipUntilBreak()
 		return
 	}
-	if c != '"' {
-		iter.ReportError("ReadString", `expects " or n`)
-		return
-	}
-	end := iter.findStringEndWithoutEscape()
-	if end != -1 {
-		// fast path: reuse the underlying buffer
-		ret = iter.buf[iter.head:end-1]
-		iter.head = end
-		return ret
-	}
+	iter.ReportError("ReadString", `expects " or n`)
+	return
+}
+
+func (iter *Iterator) readStringAsBytesSlowPath() (ret []byte) {
 	str := make([]byte, 0, 8)
+	var c byte
 	for iter.Error == nil {
 		c = iter.readByte()
 		if c == '"' {
@@ -541,79 +552,11 @@ func (iter *Iterator) ReadArray() (ret bool) {
 	case ',':
 		return true
 	default:
-		iter.ReportError("ReadArray", "expect [ or , or ] or n")
-		return
-	}
-}
-
-func (iter *Iterator) ReadObject() (ret string) {
-	c := iter.nextToken()
-	if iter.Error != nil {
-		return
-	}
-	switch c {
-	case 'n': {
-		iter.skipUntilBreak()
-		if iter.Error != nil {
-			return
-		}
-		return "" // null
-	}
-	case '{': {
-		c = iter.nextToken()
-		if iter.Error != nil {
-			return
-		}
-		switch c {
-		case '}':
-			return "" // end of object
-		case '"':
-			iter.unreadByte()
-			return iter.readObjectField()
-		default:
-			iter.ReportError("ReadObject", `expect " after {`)
-			return
-		}
-	}
-	case ',':
-		return iter.readObjectField()
-	case '}':
-		return "" // end of object
-	default:
-		iter.ReportError("ReadObject", `expect { or , or } or n`)
+		iter.ReportError("ReadArray", "expect [ or , or ] or n, but found: " + string([]byte{c}))
 		return
 	}
 }
 
-func (iter *Iterator) readObjectField() (ret string) {
-	str := iter.readStringAsBytes()
-	if iter.skipWhitespacesWithoutLoadMore() {
-		if ret == "" {
-			ret = string(str);
-		}
-		if !iter.loadMore() {
-			return
-		}
-	}
-	if iter.buf[iter.head] != ':' {
-		iter.ReportError("ReadObject", "expect : after object field")
-		return
-	}
-	iter.head++
-	if iter.skipWhitespacesWithoutLoadMore() {
-		if ret == "" {
-			ret = string(str);
-		}
-		if !iter.loadMore() {
-			return
-		}
-	}
-	if ret == "" {
-		return *(*string)(unsafe.Pointer(&str))
-	}
-	return ret
-}
-
 func (iter *Iterator) ReadFloat32() (ret float32) {
 	strBuf := [8]byte{}
 	str := strBuf[0:0]
@@ -681,7 +624,7 @@ func (iter *Iterator) ReadFloat64() (ret float64) {
 }
 
 func (iter *Iterator) ReadBool() (ret bool) {
-	c := iter.readByte()
+	c := iter.nextToken()
 	if iter.Error != nil {
 		return
 	}
@@ -714,7 +657,7 @@ func (iter *Iterator) ReadBase64() (ret []byte) {
 }
 
 func (iter *Iterator) ReadNull() (ret bool) {
-	c := iter.readByte()
+	c := iter.nextToken()
 	if c == 'n' {
 		iter.skipUntilBreak()
 		return true
@@ -724,7 +667,7 @@ func (iter *Iterator) ReadNull() (ret bool) {
 }
 
 func (iter *Iterator) Skip() {
-	c := iter.readByte()
+	c := iter.nextToken()
 	switch c {
 	case '"':
 		iter.skipString()

+ 3 - 0
jsoniter_any_test.go

@@ -8,6 +8,9 @@ import (
 func Test_read_string_as_any(t *testing.T) {
 	iter := ParseString(`[1, {"hello": "world"}, 2]`)
 	any := iter.ReadAny()
+	if iter.Error != nil {
+		t.Fatal(iter.Error)
+	}
 	if any.ToString(1, "hello") != "world" {
 		t.FailNow()
 	}

+ 9 - 29
jsoniter_customize_test.go

@@ -45,45 +45,25 @@ func Test_customize_field_decoder(t *testing.T) {
 	}
 }
 
-func Test_customize_field_by_extension(t *testing.T) {
-	RegisterExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc) {
-		if (type_.String() == "jsoniter.Tom" && field.Name == "field1") {
-			return []string{"field-1"}, func(ptr unsafe.Pointer, iter *Iterator) {
-				*((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
-			}
-		}
-		return nil, nil
-	})
-	tom := Tom{}
-	err := Unmarshal([]byte(`{"field-1": 100}`), &tom)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if tom.field1 != "100" {
-		t.Fatal(tom.field1)
-	}
-}
-
-type Jerry struct {
+type TestObject1 struct {
 	field1 string
 }
 
-func Test_customize_type_by_extension(t *testing.T) {
+func Test_customize_field_by_extension(t *testing.T) {
 	RegisterExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc) {
-		if (type_.String() == "jsoniter.Jerry" && field == nil) {
-			return nil, func(ptr unsafe.Pointer, iter *Iterator) {
-				obj := (*Jerry)(ptr)
-				obj.field1 = iter.ReadString()
+		if (type_.String() == "jsoniter.TestObject1" && field.Name == "field1") {
+			return []string{"field-1"}, func(ptr unsafe.Pointer, iter *Iterator) {
+				*((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
 			}
 		}
 		return nil, nil
 	})
-	jerry := Jerry{}
-	err := Unmarshal([]byte(`"100"`), &jerry)
+	obj := TestObject1{}
+	err := Unmarshal([]byte(`{"field-1": 100}`), &obj)
 	if err != nil {
 		t.Fatal(err)
 	}
-	if jerry.field1 != "100" {
-		t.Fatal(jerry.field1)
+	if obj.field1 != "100" {
+		t.Fatal(obj.field1)
 	}
 }

+ 15 - 15
jsoniter_large_file_test.go

@@ -7,21 +7,21 @@ import (
 	"io/ioutil"
 )
 
-func Test_large_file(t *testing.T) {
-	file, err := os.Open("/tmp/large-file.json")
-	if err != nil {
-		t.Fatal(err)
-	}
-	iter := Parse(file, 4096)
-	count := 0
-	for iter.ReadArray() {
-		iter.Skip()
-		count++
-	}
-	if count != 11351 {
-		t.Fatal(count)
-	}
-}
+//func Test_large_file(t *testing.T) {
+//	file, err := os.Open("/tmp/large-file.json")
+//	if err != nil {
+//		t.Fatal(err)
+//	}
+//	iter := Parse(file, 4096)
+//	count := 0
+//	for iter.ReadArray() {
+//		iter.Skip()
+//		count++
+//	}
+//	if count != 11351 {
+//		t.Fatal(count)
+//	}
+//}
 
 
 func Benchmark_jsoniter_large_file(b *testing.B) {

+ 6 - 5
jsoniter_reflect_test.go

@@ -297,13 +297,14 @@ type StructOfTagOne struct {
 
 func Benchmark_jsoniter_reflect(b *testing.B) {
 	b.ReportAllocs()
+	iter := Create()
+	struct_ := &StructOfTagOne{}
+	//var struct_ *StructOfTagOne
+	input := []byte(`{"field3": "100", "field4": "100"}`)
+	//input := []byte(`null`)
 	for n := 0; n < b.N; n++ {
-		iter := ParseString(`{"field3": "100"}`)
-		struct_ := StructOfTagOne{}
+		iter.ResetBytes(input)
 		iter.Read(&struct_)
-		//iter := ParseString(`[1,2,3]`)
-		//var array []int
-		//iter.Read(&array)
 	}
 }