1
0
mirror of https://github.com/json-iterator/go.git synced 2025-02-01 19:14:29 +02:00

optimize read string

This commit is contained in:
Tao Wen 2016-12-06 14:23:59 +08:00
parent c457aeaac2
commit c44e7c496a
3 changed files with 70 additions and 4 deletions

View File

@ -271,7 +271,40 @@ func (iter *Iterator) ReadInt64() (ret int64) {
} }
func (iter *Iterator) ReadString() (ret string) { func (iter *Iterator) ReadString() (ret string) {
str := make([]byte, 0, 8) return string(iter.ReadStringAsBytes())
}
// Tries to find the end of string
// Support if string contains escaped quote symbols.
func stringEnd(data []byte) (int, bool) {
escaped := false
for i, c := range data {
if c == '"' {
if !escaped {
return i + 1, false
} else {
j := i - 1
for {
if j < 0 || data[j] != '\\' {
return i + 1, true // even number of backslashes
}
j--
if j < 0 || data[j] != '\\' {
break // odd number of backslashes
}
j--
}
}
} else if c == '\\' {
escaped = true
}
}
return -1, escaped
}
func (iter *Iterator) ReadStringAsBytes() (ret []byte) {
c := iter.readByte() c := iter.readByte()
if c == 'n' { if c == 'n' {
iter.skipNull() iter.skipNull()
@ -281,10 +314,17 @@ func (iter *Iterator) ReadString() (ret string) {
iter.ReportError("ReadString", `expects " or n`) iter.ReportError("ReadString", `expects " or n`)
return return
} }
end, escaped := stringEnd(iter.buf[iter.head:])
if end != -1 && !escaped {
ret = iter.buf[iter.head:iter.head+end-1]
iter.head += end
return ret
}
str := make([]byte, 0, 8)
for iter.Error == nil { for iter.Error == nil {
c = iter.readByte() c = iter.readByte()
if c == '"' { if c == '"' {
return string(str) return str
} }
if c == '\\' { if c == '\\' {
c = iter.readByte() c = iter.readByte()
@ -543,7 +583,8 @@ func (iter *Iterator) ReadObject() (ret string) {
} }
func (iter *Iterator) readObjectField() (ret string) { func (iter *Iterator) readObjectField() (ret string) {
field := iter.ReadString() str := iter.ReadStringAsBytes()
field := *(*string)(unsafe.Pointer(&str))
if iter.Error != nil { if iter.Error != nil {
return return
} }

View File

@ -3,6 +3,7 @@ package jsoniter
import ( import (
"testing" "testing"
"encoding/json" "encoding/json"
"fmt"
) )
func Test_empty_object(t *testing.T) { func Test_empty_object(t *testing.T) {
@ -17,6 +18,7 @@ func Test_one_field(t *testing.T) {
iter := ParseString(`{"a": "b"}`) iter := ParseString(`{"a": "b"}`)
field := iter.ReadObject() field := iter.ReadObject()
if field != "a" { if field != "a" {
fmt.Println(iter.Error)
t.Fatal(field) t.Fatal(field)
} }
value := iter.ReadString() value := iter.ReadString()

View File

@ -72,6 +72,18 @@ func Test_string_escape_unicode_with_surrogate(t *testing.T) {
} }
} }
func Test_string_as_bytes(t *testing.T) {
iter := Parse(bytes.NewBufferString(`"hello""world"`), 4096)
val := string(iter.ReadStringAsBytes())
if val != "hello" {
t.Fatal(val)
}
val = string(iter.ReadStringAsBytes())
if val != "world" {
t.Fatal(val)
}
}
func Benchmark_jsoniter_unicode(b *testing.B) { func Benchmark_jsoniter_unicode(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter := ParseString(`"\ud83d\udc4a"`) iter := ParseString(`"\ud83d\udc4a"`)
@ -80,12 +92,23 @@ func Benchmark_jsoniter_unicode(b *testing.B) {
} }
func Benchmark_jsoniter_ascii(b *testing.B) { func Benchmark_jsoniter_ascii(b *testing.B) {
iter := ParseString(`"hello, world!"`)
b.ResetTimer()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter := ParseString(`"hello"`) iter.Reuse(iter.buf)
iter.ReadString() iter.ReadString()
} }
} }
func Benchmark_jsoniter_string_as_bytes(b *testing.B) {
iter := ParseString(`"hello, world!"`)
b.ResetTimer()
for n := 0; n < b.N; n++ {
iter.Reuse(iter.buf)
iter.ReadStringAsBytes()
}
}
func Benchmark_json_unicode(b *testing.B) { func Benchmark_json_unicode(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
result := "" result := ""