2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-21 00:46:43 +08:00

fix:(ast) quote string when node.MarshalJSON() (#155)

Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com>
This commit is contained in:
Yi Duan 2021-12-15 19:20:18 +08:00 committed by GitHub
parent 8405d84e31
commit e80837a84d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 5 deletions

View file

@ -17,13 +17,17 @@
package ast
import (
`reflect`
`sync`
`unsafe`
`github.com/bytedance/sonic/encoder`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/rt`
)
const (
_MaxBuffer = 4 * 1024 // 4KB buffer size
_MaxBuffer = 1024 // 1KB buffer size
)
const (
@ -113,10 +117,45 @@ func (self *Node) encodeNumber(buf *[]byte) error {
return nil
}
var typeByte = rt.UnpackType(reflect.TypeOf(byte(0)))
func quote(buf *[]byte, sp unsafe.Pointer, nb int) {
b := (*rt.GoSlice)(unsafe.Pointer(buf))
// input buffer
for nb > 0 {
// output buffer
dp := unsafe.Pointer(uintptr(b.Ptr) + uintptr(b.Len))
dn := b.Cap - b.Len
// call native.Quote, dn is byte count it outputs
ret := native.Quote(sp, nb, dp, &dn, 0)
// update *buf length
b.Len += dn
// no need more output
if ret >= 0 {
break
}
// double buf size
*b = growslice(typeByte, *b, b.Cap * 2)
// ret is the complement of consumed input
ret = ^ret
// update input buffer
nb -= ret
sp = unsafe.Pointer(uintptr(sp) + uintptr(ret))
}
}
func (self *Node) encodeString(buf *[]byte) error {
str := addr2str(self.p, self.v)
*buf = append(*buf, '"')
*buf = append(*buf, str...)
nb := int(self.v)
if nb == 0 {
*buf = append(*buf, '"')
return nil
}
quote(buf, self.p, nb)
*buf = append(*buf, '"')
return nil
}
@ -156,7 +195,14 @@ func (self *Node) encodeArray(buf *[]byte) error {
func (self *Pair) encode(buf *[]byte) error {
*buf = append(*buf, '"')
*buf = append(*buf, self.Key...)
sptr := (*rt.GoString)(unsafe.Pointer(&self.Key))
if sptr.Len == 0 {
*buf = append(*buf, '"', ':')
return self.Value.encode(buf)
}
quote(buf, sptr.Ptr, sptr.Len)
*buf = append(*buf, '"', ':')
return self.Value.encode(buf)
}

View file

@ -72,6 +72,10 @@ func TestEncodeValue(t *testing.T) {
if err != nil {
t.Fatal(err)
}
quote, err := encoder.Encode(_TwitterJson, 0)
if err != nil {
t.Fatal(err)
}
type Case struct {
node Node
exp string
@ -83,9 +87,12 @@ func TestEncodeValue(t *testing.T) {
{NewBool(false), "false", false},
{NewNumber("0.0"), "0.0", false},
{NewString(""), `""`, false},
{NewString("\"\""), `"\"\""`, false},
{NewString(_TwitterJson), string(quote), false},
{NewArray([]Node{}), "[]", false},
{NewArray([]Node{NewBool(true), NewString("true")}), `[true,"true"]`, false},
{NewArray([]Node{NewBool(true), NewString("true"), NewString("\t")}), `[true,"true","\t"]`, false},
{NewObject([]Pair{Pair{"a", NewNull()}, Pair{"b", NewNumber("0")}}), `{"a":null,"b":0}`, false},
{NewObject([]Pair{Pair{"\ta", NewString("\t")}, Pair{"\bb", NewString("\b")}, Pair{"\nb", NewString("\n")}, Pair{"\ra", NewString("\r")}}), `{"\ta":"\t","\bb":"\b","\nb":"\n","\ra":"\r"}`, false},
{NewObject([]Pair{}), `{}`, false},
{NewBytes([]byte("hello, world")), `"aGVsbG8sIHdvcmxk"`, false},
{NewAny(obj), string(buf), false},
@ -145,6 +152,10 @@ func BenchmarkEncodeRaw(b *testing.B) {
if e != nil {
b.Fatal(root)
}
_, err := root.MarshalJSON()
if err != nil {
b.Fatal(err)
}
b.SetBytes(int64(len(data)))
b.ResetTimer()
for i:=0; i<b.N; i++ {
@ -161,6 +172,11 @@ func BenchmarkEncodeSkip(b *testing.B) {
if e != 0 {
b.Fatal(root)
}
root.skipAllKey()
_, err := root.MarshalJSON()
if err != nil {
b.Fatal(err)
}
b.SetBytes(int64(len(data)))
b.ResetTimer()
for i:=0; i<b.N; i++ {
@ -178,6 +194,10 @@ func BenchmarkEncodeLoad(b *testing.B) {
b.Fatal(root)
}
root.loadAllKey()
_, err := root.MarshalJSON()
if err != nil {
b.Fatal(err)
}
b.SetBytes(int64(len(data)))
b.ResetTimer()
for i:=0; i<b.N; i++ {