1
0
mirror of https://github.com/json-iterator/go.git synced 2025-03-23 21:09:11 +02:00
This commit is contained in:
Tao Wen 2016-12-06 13:48:03 +08:00
parent 6a46bc9513
commit c457aeaac2
2 changed files with 92 additions and 27 deletions

View File

@ -26,7 +26,6 @@ func init() {
} }
} }
type Iterator struct { type Iterator struct {
reader io.Reader reader io.Reader
buf []byte buf []byte
@ -57,14 +56,30 @@ func ParseBytes(input []byte) *Iterator {
return iter return iter
} }
func (iter *Iterator) Reuse(input []byte) *Iterator {
// only for benchmarking
iter.reader = nil
iter.Error = nil
iter.buf = input
iter.head = 0
iter.tail = len(input)
iter.skipWhitespaces()
return iter
}
func ParseString(input string) *Iterator { func ParseString(input string) *Iterator {
return ParseBytes([]byte(input)) return ParseBytes([]byte(input))
} }
func (iter *Iterator) skipWhitespaces() { func (iter *Iterator) skipWhitespaces() {
c := iter.readByte() c := iter.readByte()
for c == ' ' || c == '\n' || c == '\t' { for {
c = iter.readByte() switch c {
case ' ', '\n', '\t', 'r':
c = iter.readByte()
continue
}
break
} }
iter.unreadByte() iter.unreadByte()
} }
@ -258,29 +273,20 @@ func (iter *Iterator) ReadInt64() (ret int64) {
func (iter *Iterator) ReadString() (ret string) { func (iter *Iterator) ReadString() (ret string) {
str := make([]byte, 0, 8) str := make([]byte, 0, 8)
c := iter.readByte() c := iter.readByte()
if iter.Error != nil { if c == 'n' {
iter.skipNull()
return return
} }
switch c { if c != '"' {
case 'n':
iter.skipNull()
if iter.Error != nil {
return
}
return ""
case '"':
// nothing
default:
iter.ReportError("ReadString", `expects " or n`) iter.ReportError("ReadString", `expects " or n`)
return return
} }
for { for iter.Error == nil {
c = iter.readByte() c = iter.readByte()
if iter.Error != nil { if c == '"' {
return return string(str)
} }
switch c { if c == '\\' {
case '\\':
c = iter.readByte() c = iter.readByte()
if iter.Error != nil { if iter.Error != nil {
return return
@ -340,12 +346,11 @@ func (iter *Iterator) ReadString() (ret string) {
`invalid escape char after \`) `invalid escape char after \`)
return return
} }
case '"': } else {
return *(*string)(unsafe.Pointer(&str))
default:
str = append(str, c) str = append(str, c)
} }
} }
return
} }
func (iter *Iterator) readU4() (ret rune) { func (iter *Iterator) readU4() (ret rune) {
@ -434,9 +439,6 @@ func (iter *Iterator) ReadArray() (ret bool) {
switch c { switch c {
case 'n': { case 'n': {
iter.skipNull() iter.skipNull()
if iter.Error != nil {
return
}
return false // null return false // null
} }
case '[': { case '[': {
@ -462,6 +464,42 @@ func (iter *Iterator) ReadArray() (ret bool) {
} }
} }
func (iter *Iterator) ReadArrayCB(cb func()) {
iter.skipWhitespaces()
c := iter.readByte()
if c == 'n' {
iter.skipNull()
return // null
}
if c != '[' {
iter.ReportError("ReadArray", "expect [ or n")
return
}
iter.skipWhitespaces()
c = iter.readByte()
if c == ']' {
return // []
} else {
iter.unreadByte()
}
for {
if iter.Error != nil {
return
}
cb()
iter.skipWhitespaces()
c = iter.readByte()
if c == ']' {
return
}
if c != ',' {
iter.ReportError("ReadArray", "expect , or ]")
return
}
iter.skipWhitespaces()
}
}
func (iter *Iterator) ReadObject() (ret string) { func (iter *Iterator) ReadObject() (ret string) {
iter.skipWhitespaces() iter.skipWhitespaces()
c := iter.readByte() c := iter.readByte()

View File

@ -50,6 +50,17 @@ func Test_two_elements(t *testing.T) {
} }
} }
func Test_two_elements_cb(t *testing.T) {
iter := ParseString(`[1,2]`)
total := int64(0)
iter.ReadArrayCB(func() {
total += iter.ReadInt64()
})
if total != 3 {
t.Fatal(total)
}
}
func Test_invalid_array(t *testing.T) { func Test_invalid_array(t *testing.T) {
iter := ParseString(`[`) iter := ParseString(`[`)
iter.ReadArray() iter.ReadArray()
@ -117,16 +128,32 @@ func Test_whitespace_before_comma(t *testing.T) {
} }
} }
func Benchmark_jsoniter_array(b *testing.B) { func Benchmark_jsoniter_array(b *testing.B) {
b.ReportAllocs()
input := []byte(`[1,2,3,4,5,6,7,8,9]`)
iter := ParseBytes(input)
b.ResetTimer()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter := ParseString(`[1,2,3]`) iter.Reuse(input)
for iter.ReadArray() { for iter.ReadArray() {
iter.ReadUint64() iter.ReadUint64()
} }
} }
} }
func Benchmark_jsoniter_array_cb(b *testing.B) {
b.ReportAllocs()
input := []byte(`[1,2,3,4,5,6,7,8,9]`)
iter := ParseBytes(input)
b.ResetTimer()
for n := 0; n < b.N; n++ {
iter.Reuse(input)
iter.ReadArrayCB(func() {
iter.ReadUint64()
})
}
}
func Benchmark_json_array(b *testing.B) { func Benchmark_json_array(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
result := []interface{}{} result := []interface{}{}