1
0
mirror of https://github.com/json-iterator/go.git synced 2024-11-27 08:30:57 +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"
)
/*
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

View File

@ -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")
iter.ReportError("ReadArray", "expect [ or , or ] or n, but found: " + string([]byte{c}))
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) {
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()

View File

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

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) {
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) {
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
}
}
return nil, nil
})
tom := Tom{}
err := Unmarshal([]byte(`{"field-1": 100}`), &tom)
obj := TestObject1{}
err := Unmarshal([]byte(`{"field-1": 100}`), &obj)
if err != nil {
t.Fatal(err)
}
if tom.field1 != "100" {
t.Fatal(tom.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)
if obj.field1 != "100" {
t.Fatal(obj.field1)
}
}

View File

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

View File

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