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

fix read any; reuse existing obj for optional

This commit is contained in:
Tao Wen 2017-01-05 13:53:38 +08:00
parent 247a23a637
commit 97849e019f
7 changed files with 195 additions and 153 deletions

85
feature_iter_object.go Normal file
View File

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

View File

@ -11,6 +11,15 @@ import (
"strconv" "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 { type Decoder interface {
decode(ptr unsafe.Pointer, iter *Iterator) decode(ptr unsafe.Pointer, iter *Iterator)
} }
@ -133,7 +142,7 @@ type stringNumberDecoder struct {
} }
func (decoder *stringNumberDecoder) decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *stringNumberDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
c := iter.readByte() c := iter.nextToken()
if c != '"' { if c != '"' {
iter.ReportError("stringNumberDecoder", `expect "`) iter.ReportError("stringNumberDecoder", `expect "`)
return return
@ -158,9 +167,15 @@ func (decoder *optionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNull() { if iter.ReadNull() {
*((*unsafe.Pointer)(ptr)) = nil *((*unsafe.Pointer)(ptr)) = nil
} else { } else {
value := reflect.New(decoder.valueType) if *((*unsafe.Pointer)(ptr)) == nil {
decoder.valueDecoder.decode(unsafe.Pointer(value.Pointer()), iter) // pointer to null, we have to allocate memory to hold the value
*((*uintptr)(ptr)) = value.Pointer() 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) { 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 { switch field {
case decoder.fieldName1: case decoder.fieldName1:
decoder.fieldDecoder1.decode(ptr, iter) 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() { for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
elem := reflect.New(decoder.elemType) elem := reflect.New(decoder.elemType)
decoder.elemDecoder.decode(unsafe.Pointer(elem.Pointer()), iter) 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()) 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()) dst := unsafe.Pointer(reflect.MakeSlice(sliceType, newLen, newCap).Pointer())
// copy old array into new array
originalBytesCount := uintptr(slice.Len) * elementType.Size() originalBytesCount := uintptr(slice.Len) * elementType.Size()
srcPtr := (*[1 << 30]byte)(slice.Data) srcPtr := (*[1 << 30]byte)(slice.Data)
dstPtr := (*[1 << 30]byte)(dst) dstPtr := (*[1 << 30]byte)(dst)
@ -554,9 +588,13 @@ func (iter *Iterator) readNumber() (ret *Any) {
str = append(str, c) str = append(str, c)
continue continue
default: default:
iter.head = i
hasMore = false hasMore = false
break break
} }
if !hasMore {
break
}
} }
if hasMore { if hasMore {
if !iter.loadMore() { if !iter.loadMore() {
@ -632,14 +670,6 @@ func decoderOfPtr(type_ reflect.Type) (Decoder, error) {
if typeName == "jsoniter.Any" { if typeName == "jsoniter.Any" {
return &anyDecoder{}, nil 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] typeDecoder := typeDecoders[typeName]
if typeDecoder != nil { if typeDecoder != nil {
return typeDecoder, nil return typeDecoder, nil

View File

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

View File

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

View File

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

View File

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

View File

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