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:
parent
247a23a637
commit
97849e019f
85
feature_iter_object.go
Normal file
85
feature_iter_object.go
Normal 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
|
||||||
|
}
|
@ -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
|
||||||
|
125
jsoniter.go
125
jsoniter.go
@ -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()
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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) {
|
||||||
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user