1
0
mirror of https://github.com/json-iterator/go.git synced 2025-03-23 21:09:11 +02:00

support skip

This commit is contained in:
Tao Wen 2016-12-02 00:13:13 +08:00
parent f96cc49fd4
commit 05a9df4749
2 changed files with 258 additions and 14 deletions

View File

@ -43,7 +43,7 @@ func ParseString(input string) *Iterator {
func (iter *Iterator) skipWhitespaces() {
c := iter.readByte()
for c == ' ' {
for c == ' ' || c == '\n' {
c = iter.readByte()
}
iter.unreadByte()
@ -326,7 +326,9 @@ func (iter *Iterator) ReadArray() (ret bool) {
}
}
case ']': return false
case ',': return true
case ',':
iter.skipWhitespaces()
return true
default:
iter.ReportError("ReadArray", "expect [ or , or ]")
return
@ -397,18 +399,8 @@ func (iter *Iterator) readObjectField() (ret string) {
func (iter *Iterator) ReadFloat64() (ret float64) {
str := make([]byte, 0, 10)
for c := iter.readByte(); iter.Error == nil; c = iter.readByte() {
switch {
case c == '+':
fallthrough
case c == '-':
fallthrough
case c == '.':
fallthrough
case c == 'e':
fallthrough
case c == 'E':
fallthrough
case c > '0' && c < '9':
switch c {
case '-', '+', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
str = append(str, c)
default:
iter.unreadByte()
@ -430,3 +422,117 @@ func (iter *Iterator) ReadFloat64() (ret float64) {
}
return
}
func (iter *Iterator) Skip() {
c := iter.readByte()
if iter.Error != nil {
return
}
switch c {
case '"':
iter.skipString()
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
iter.skipNumber()
case '[':
iter.skipArray()
case '{':
iter.skipObject()
default:
iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c))
return
}
}
func (iter *Iterator) skipString() {
for c := iter.readByte(); iter.Error == nil; c = iter.readByte() {
switch c {
case '"':
return // end of string found
case '\\':
iter.readByte() // " after \\ does not count
if iter.Error != nil {
return
}
}
}
}
func (iter *Iterator) skipNumber() {
for c := iter.readByte(); iter.Error == nil; c = iter.readByte() {
switch c {
case '-', '+', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
continue
default:
iter.unreadByte()
return
}
}
}
func (iter *Iterator) skipArray() {
for {
iter.skipWhitespaces()
c := iter.readByte()
if iter.Error != nil {
return
}
if c == ']' {
return
}
iter.unreadByte()
iter.Skip()
iter.skipWhitespaces()
c = iter.readByte()
if iter.Error != nil {
return
}
switch c {
case ',':
iter.skipWhitespaces()
continue
case ']':
return
default:
iter.ReportError("skipArray", "expects , or ]")
return
}
}
}
func (iter *Iterator) skipObject() {
for {
iter.skipWhitespaces()
c := iter.readByte()
if c != '"' {
iter.ReportError("skipObject", `expects "`)
return
}
iter.skipString()
iter.skipWhitespaces()
c = iter.readByte()
if iter.Error != nil {
return
}
if c != ':' {
iter.ReportError("skipObject", `expects :`)
return
}
iter.skipWhitespaces()
iter.Skip()
iter.skipWhitespaces()
c = iter.readByte()
if iter.Error != nil {
return
}
switch c {
case ',':
iter.skipWhitespaces()
continue
case '}':
return // end of object
default:
iter.ReportError("skipObject", "expects , or }")
return
}
}
}

138
jsoniter_skip_test.go Normal file
View File

@ -0,0 +1,138 @@
package jsoniter
import (
"testing"
"encoding/json"
)
func Test_skip_string(t *testing.T) {
iter := ParseString(`["a", "b"]`)
iter.ReadArray()
iter.Skip()
iter.ReadArray()
if iter.ReadString() != "b" {
t.FailNow()
}
}
func Test_skip_string_with_escape(t *testing.T) {
iter := ParseString(`["a\"", "b"]`)
iter.ReadArray()
iter.Skip()
iter.ReadArray()
if iter.ReadString() != "b" {
t.FailNow()
}
}
func Test_skip_number(t *testing.T) {
iter := ParseString(`[-0.12, "b"]`)
iter.ReadArray()
iter.Skip()
iter.ReadArray()
if iter.ReadString() != "b" {
t.FailNow()
}
}
func Test_skip_array(t *testing.T) {
iter := ParseString(`[[1, [2, [3], 4]], "b"]`)
iter.ReadArray()
iter.Skip()
iter.ReadArray()
if iter.ReadString() != "b" {
t.FailNow()
}
}
func Test_skip_object(t *testing.T) {
iter := ParseString(`[ {"a" : {"b": "c"}, "d": 102 }, "b"]`)
iter.ReadArray()
iter.Skip()
iter.ReadArray()
if iter.ReadString() != "b" {
t.FailNow()
}
}
func Test_skip_nested(t *testing.T) {
iter := ParseString(`[ {"a" : [{"b": "c"}], "d": 102 }, "b"]`)
iter.ReadArray()
iter.Skip()
iter.ReadArray()
if iter.ReadString() != "b" {
t.FailNow()
}
}
type TestResp struct {
Code uint64
}
func Benchmark_jsoniter_skip(b *testing.B) {
for n := 0; n < b.N; n++ {
result := TestResp{}
iter := ParseString(`
{
"_shards":{
"total" : 5,
"successful" : 5,
"failed" : 0
},
"code": 200,
"hits":{
"total" : 1,
"hits" : [
{
"_index" : "twitter",
"_type" : "tweet",
"_id" : "1",
"_source" : {
"user" : "kimchy",
"postDate" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
}
]
}
}`)
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
switch field {
case "code":
result.Code = iter.ReadUint64()
default:
iter.Skip()
}
}
}
}
func Benchmark_json_skip(b *testing.B) {
for n := 0; n < b.N; n++ {
result := TestResp{}
json.Unmarshal([]byte(`
{
"_shards":{
"total" : 5,
"successful" : 5,
"failed" : 0
},
"code": 200,
"hits":{
"total" : 1,
"hits" : [
{
"_index" : "twitter",
"_type" : "tweet",
"_id" : "1",
"_source" : {
"user" : "kimchy",
"postDate" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
}
]
}
}`), &result)
}
}