1
0
mirror of https://github.com/json-iterator/go.git synced 2025-04-01 21:24:21 +02:00

support null/true/false

This commit is contained in:
Tao Wen 2016-12-02 11:22:20 +08:00
parent 05a9df4749
commit ce5b193569
6 changed files with 358 additions and 31 deletions

@ -50,7 +50,12 @@ func (iter *Iterator) skipWhitespaces() {
} }
func (iter *Iterator) ReportError(operation string, msg string) { func (iter *Iterator) ReportError(operation string, msg string) {
iter.Error = fmt.Errorf("%s: %s, parsing %v at %s", operation, msg, iter.head, string(iter.buf[0:iter.tail])) peekStart := iter.head - 10
if peekStart < 0 {
peekStart = 0
}
iter.Error = fmt.Errorf("%s: %s, parsing %v ...%s... at %s", operation, msg, iter.head,
string(iter.buf[peekStart: iter.head]), string(iter.buf[0:iter.tail]))
} }
func (iter *Iterator) readByte() (ret byte) { func (iter *Iterator) readByte() (ret byte) {
@ -150,8 +155,17 @@ func (iter *Iterator) ReadString() (ret string) {
if iter.Error != nil { if iter.Error != nil {
return return
} }
if c != '"' { switch c {
iter.ReportError("ReadString", "expects quote") case 'n':
iter.skipNull()
if iter.Error != nil {
return
}
return ""
case '"':
// nothing
default:
iter.ReportError("ReadString", `expects " or n`)
return return
} }
for { for {
@ -312,6 +326,13 @@ func (iter *Iterator) ReadArray() (ret bool) {
return return
} }
switch c { switch c {
case 'n': {
iter.skipNull()
if iter.Error != nil {
return
}
return false // null
}
case '[': { case '[': {
iter.skipWhitespaces() iter.skipWhitespaces()
c = iter.readByte() c = iter.readByte()
@ -330,7 +351,7 @@ func (iter *Iterator) ReadArray() (ret bool) {
iter.skipWhitespaces() iter.skipWhitespaces()
return true return true
default: default:
iter.ReportError("ReadArray", "expect [ or , or ]") iter.ReportError("ReadArray", "expect [ or , or ] or n")
return return
} }
} }
@ -342,6 +363,13 @@ func (iter *Iterator) ReadObject() (ret string) {
return return
} }
switch c { switch c {
case 'n': {
iter.skipNull()
if iter.Error != nil {
return
}
return "" // null
}
case '{': { case '{': {
iter.skipWhitespaces() iter.skipWhitespaces()
c = iter.readByte() c = iter.readByte()
@ -373,7 +401,7 @@ func (iter *Iterator) ReadObject() (ret string) {
case '}': case '}':
return "" // end of object return "" // end of object
default: default:
iter.ReportError("ReadObject", `expect { or , or }`) iter.ReportError("ReadObject", `expect { or , or } or n`)
return return
} }
} }
@ -423,6 +451,135 @@ func (iter *Iterator) ReadFloat64() (ret float64) {
return return
} }
func (iter *Iterator) ReadBool() (ret bool) {
c := iter.readByte()
if iter.Error != nil {
return
}
switch c {
case 't':
iter.skipTrue()
if iter.Error != nil {
return
}
return true
case 'f':
iter.skipFalse()
if iter.Error != nil {
return
}
return false
default:
iter.ReportError("ReadBool", "expect t or f")
return
}
}
func (iter *Iterator) skipTrue() {
c := iter.readByte()
if iter.Error != nil {
return
}
if c != 'r' {
iter.ReportError("skipTrue", "expect r of true")
return
}
c = iter.readByte()
if iter.Error != nil {
return
}
if c != 'u' {
iter.ReportError("skipTrue", "expect u of true")
return
}
c = iter.readByte()
if iter.Error != nil {
return
}
if c != 'e' {
iter.ReportError("skipTrue", "expect e of true")
return
}
}
func (iter *Iterator) skipFalse() {
c := iter.readByte()
if iter.Error != nil {
return
}
if c != 'a' {
iter.ReportError("skipFalse", "expect a of false")
return
}
c = iter.readByte()
if iter.Error != nil {
return
}
if c != 'l' {
iter.ReportError("skipFalse", "expect l of false")
return
}
c = iter.readByte()
if iter.Error != nil {
return
}
if c != 's' {
iter.ReportError("skipFalse", "expect s of false")
return
}
c = iter.readByte()
if iter.Error != nil {
return
}
if c != 'e' {
iter.ReportError("skipFalse", "expect e of false")
return
}
}
func (iter *Iterator) ReadNull() (ret bool) {
c := iter.readByte()
if iter.Error != nil {
return
}
if c == 'n' {
iter.skipNull()
if iter.Error != nil {
return
}
return true
}
iter.unreadByte()
return false
}
func (iter *Iterator) skipNull() {
c := iter.readByte()
if iter.Error != nil {
return
}
if c != 'u' {
iter.ReportError("skipNull", "expect u of null")
return
}
c = iter.readByte()
if iter.Error != nil {
return
}
if c != 'l' {
iter.ReportError("skipNull", "expect l of null")
return
}
c = iter.readByte()
if iter.Error != nil {
return
}
if c != 'l' {
iter.ReportError("skipNull", "expect l of null")
return
}
}
func (iter *Iterator) Skip() { func (iter *Iterator) Skip() {
c := iter.readByte() c := iter.readByte()
if iter.Error != nil { if iter.Error != nil {
@ -437,6 +594,12 @@ func (iter *Iterator) Skip() {
iter.skipArray() iter.skipArray()
case '{': case '{':
iter.skipObject() iter.skipObject()
case 't':
iter.skipTrue()
case 'f':
iter.skipFalse()
case 'n':
iter.skipNull()
default: default:
iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c)) iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c))
return return
@ -500,9 +663,22 @@ func (iter *Iterator) skipArray() {
} }
func (iter *Iterator) skipObject() { func (iter *Iterator) skipObject() {
iter.skipWhitespaces()
c := iter.readByte()
if iter.Error != nil {
return
}
if c == '}' {
return // end of object
} else {
iter.unreadByte()
}
for { for {
iter.skipWhitespaces() iter.skipWhitespaces()
c := iter.readByte() c := iter.readByte()
if iter.Error != nil {
return
}
if c != '"' { if c != '"' {
iter.ReportError("skipObject", `expects "`) iter.ReportError("skipObject", `expects "`)
return return

17
jsoniter_bool_test.go Normal file

@ -0,0 +1,17 @@
package jsoniter
import "testing"
func Test_true(t *testing.T) {
iter := ParseString(`true`)
if iter.ReadBool() != true {
t.FailNow()
}
}
func Test_false(t *testing.T) {
iter := ParseString(`false`)
if iter.ReadBool() != false {
t.FailNow()
}
}

@ -0,0 +1,50 @@
package jsoniter
import (
"testing"
"os"
"encoding/json"
"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 Benchmark_jsoniter_large_file(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
file, _ := os.Open("/tmp/large-file.json")
iter := Parse(file, 4096)
count := 0
for iter.ReadArray() {
iter.Skip()
count++
}
file.Close()
}
}
func Benchmark_json_large_file(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
file, _ := os.Open("/tmp/large-file.json")
bytes, _ := ioutil.ReadAll(file)
file.Close()
result := []struct{}{}
json.Unmarshal(bytes, &result)
}
}

@ -55,27 +55,31 @@ func Benchmark_jsoniter_nested(b *testing.B) {
for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() { for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
switch l1Field { switch l1Field {
case "hello": case "hello":
l2Array := make([]Level2, 0, 2) l1.Hello = readLevel1Hello(iter)
for iter.ReadArray() {
l2 := Level2{}
for l2Field := iter.ReadObject(); l2Field != ""; l2Field = iter.ReadObject() {
switch l2Field {
case "world":
l2.World = iter.ReadString()
default:
iter.ReportError("bind l2", "unexpected field: " + l2Field)
}
}
l2Array = append(l2Array, l2)
}
l1.Hello = l2Array
default: default:
iter.ReportError("bind l1", "unexpected field: " + l1Field) iter.Skip()
} }
} }
} }
} }
func readLevel1Hello(iter *Iterator) []Level2 {
l2Array := make([]Level2, 0, 2)
for iter.ReadArray() {
l2 := Level2{}
for l2Field := iter.ReadObject(); l2Field != ""; l2Field = iter.ReadObject() {
switch l2Field {
case "world":
l2.World = iter.ReadString()
default:
iter.Skip()
}
}
l2Array = append(l2Array, l2)
}
return l2Array
}
func Benchmark_json_nested(b *testing.B) { func Benchmark_json_nested(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
l1 := Level1{} l1 := Level1{}

58
jsoniter_null_test.go Normal file

@ -0,0 +1,58 @@
package jsoniter
import (
"testing"
)
func Test_null(t *testing.T) {
iter := ParseString(`null`)
if iter.ReadNull() != true {
t.FailNow()
}
}
func Test_null_object(t *testing.T) {
iter := ParseString(`[null,"a"]`)
iter.ReadArray()
if iter.ReadObject() != "" {
t.FailNow()
}
iter.ReadArray()
if iter.ReadString() != "a" {
t.FailNow()
}
}
func Test_null_array(t *testing.T) {
iter := ParseString(`[null,"a"]`)
iter.ReadArray()
if iter.ReadArray() != false {
t.FailNow()
}
iter.ReadArray()
if iter.ReadString() != "a" {
t.FailNow()
}
}
func Test_null_string(t *testing.T) {
iter := ParseString(`[null,"a"]`)
iter.ReadArray()
if iter.ReadString() != "" {
t.FailNow()
}
iter.ReadArray()
if iter.ReadString() != "a" {
t.FailNow()
}
}
func Test_null_skip(t *testing.T) {
iter := ParseString(`[null,"a"]`)
iter.ReadArray()
iter.Skip()
iter.ReadArray()
if iter.ReadString() != "a" {
t.FailNow()
}
}

@ -45,6 +45,16 @@ func Test_skip_array(t *testing.T) {
} }
} }
func Test_skip_empty_array(t *testing.T) {
iter := ParseString(`[ [ ], "b"]`)
iter.ReadArray()
iter.Skip()
iter.ReadArray()
if iter.ReadString() != "b" {
t.FailNow()
}
}
func Test_skip_object(t *testing.T) { func Test_skip_object(t *testing.T) {
iter := ParseString(`[ {"a" : {"b": "c"}, "d": 102 }, "b"]`) iter := ParseString(`[ {"a" : {"b": "c"}, "d": 102 }, "b"]`)
iter.ReadArray() iter.ReadArray()
@ -55,6 +65,16 @@ func Test_skip_object(t *testing.T) {
} }
} }
func Test_skip_empty_object(t *testing.T) {
iter := ParseString(`[ { }, "b"]`)
iter.ReadArray()
iter.Skip()
iter.ReadArray()
if iter.ReadString() != "b" {
t.FailNow()
}
}
func Test_skip_nested(t *testing.T) { func Test_skip_nested(t *testing.T) {
iter := ParseString(`[ {"a" : [{"b": "c"}], "d": 102 }, "b"]`) iter := ParseString(`[ {"a" : [{"b": "c"}], "d": 102 }, "b"]`)
iter.ReadArray() iter.ReadArray()
@ -70,16 +90,13 @@ type TestResp struct {
} }
func Benchmark_jsoniter_skip(b *testing.B) { func Benchmark_jsoniter_skip(b *testing.B) {
for n := 0; n < b.N; n++ { input := []byte(`
result := TestResp{}
iter := ParseString(`
{ {
"_shards":{ "_shards":{
"total" : 5, "total" : 5,
"successful" : 5, "successful" : 5,
"failed" : 0 "failed" : 0
}, },
"code": 200,
"hits":{ "hits":{
"total" : 1, "total" : 1,
"hits" : [ "hits" : [
@ -94,8 +111,12 @@ func Benchmark_jsoniter_skip(b *testing.B) {
} }
} }
] ]
} },
"code": 200
}`) }`)
for n := 0; n < b.N; n++ {
result := TestResp{}
iter := ParseBytes(input)
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
switch field { switch field {
case "code": case "code":
@ -108,16 +129,13 @@ func Benchmark_jsoniter_skip(b *testing.B) {
} }
func Benchmark_json_skip(b *testing.B) { func Benchmark_json_skip(b *testing.B) {
for n := 0; n < b.N; n++ { input := []byte(`
result := TestResp{}
json.Unmarshal([]byte(`
{ {
"_shards":{ "_shards":{
"total" : 5, "total" : 5,
"successful" : 5, "successful" : 5,
"failed" : 0 "failed" : 0
}, },
"code": 200,
"hits":{ "hits":{
"total" : 1, "total" : 1,
"hits" : [ "hits" : [
@ -132,7 +150,11 @@ func Benchmark_json_skip(b *testing.B) {
} }
} }
] ]
} },
}`), &result) "code": 200
}`)
for n := 0; n < b.N; n++ {
result := TestResp{}
json.Unmarshal(input, &result)
} }
} }