mirror of
https://github.com/ii64/sonic.git
synced 2026-06-23 09:56:44 +08:00
fix:(ast) quote string when node.MarshalJSON() (#155)
Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com>
This commit is contained in:
parent
8405d84e31
commit
e80837a84d
2 changed files with 71 additions and 5 deletions
|
|
@ -17,13 +17,17 @@
|
||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
`reflect`
|
||||||
`sync`
|
`sync`
|
||||||
|
`unsafe`
|
||||||
|
|
||||||
`github.com/bytedance/sonic/encoder`
|
`github.com/bytedance/sonic/encoder`
|
||||||
|
`github.com/bytedance/sonic/internal/native`
|
||||||
|
`github.com/bytedance/sonic/internal/rt`
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_MaxBuffer = 4 * 1024 // 4KB buffer size
|
_MaxBuffer = 1024 // 1KB buffer size
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -113,10 +117,45 @@ func (self *Node) encodeNumber(buf *[]byte) error {
|
||||||
return nil
|
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 {
|
func (self *Node) encodeString(buf *[]byte) error {
|
||||||
str := addr2str(self.p, self.v)
|
|
||||||
*buf = append(*buf, '"')
|
*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, '"')
|
*buf = append(*buf, '"')
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +195,14 @@ func (self *Node) encodeArray(buf *[]byte) error {
|
||||||
|
|
||||||
func (self *Pair) encode(buf *[]byte) error {
|
func (self *Pair) encode(buf *[]byte) error {
|
||||||
*buf = append(*buf, '"')
|
*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, '"', ':')
|
*buf = append(*buf, '"', ':')
|
||||||
return self.Value.encode(buf)
|
return self.Value.encode(buf)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,10 @@ func TestEncodeValue(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
quote, err := encoder.Encode(_TwitterJson, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
type Case struct {
|
type Case struct {
|
||||||
node Node
|
node Node
|
||||||
exp string
|
exp string
|
||||||
|
|
@ -83,9 +87,12 @@ func TestEncodeValue(t *testing.T) {
|
||||||
{NewBool(false), "false", false},
|
{NewBool(false), "false", false},
|
||||||
{NewNumber("0.0"), "0.0", false},
|
{NewNumber("0.0"), "0.0", false},
|
||||||
{NewString(""), `""`, false},
|
{NewString(""), `""`, false},
|
||||||
|
{NewString("\"\""), `"\"\""`, false},
|
||||||
|
{NewString(_TwitterJson), string(quote), false},
|
||||||
{NewArray([]Node{}), "[]", 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{"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},
|
{NewObject([]Pair{}), `{}`, false},
|
||||||
{NewBytes([]byte("hello, world")), `"aGVsbG8sIHdvcmxk"`, false},
|
{NewBytes([]byte("hello, world")), `"aGVsbG8sIHdvcmxk"`, false},
|
||||||
{NewAny(obj), string(buf), false},
|
{NewAny(obj), string(buf), false},
|
||||||
|
|
@ -145,6 +152,10 @@ func BenchmarkEncodeRaw(b *testing.B) {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
b.Fatal(root)
|
b.Fatal(root)
|
||||||
}
|
}
|
||||||
|
_, err := root.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
b.SetBytes(int64(len(data)))
|
b.SetBytes(int64(len(data)))
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i:=0; i<b.N; i++ {
|
for i:=0; i<b.N; i++ {
|
||||||
|
|
@ -161,6 +172,11 @@ func BenchmarkEncodeSkip(b *testing.B) {
|
||||||
if e != 0 {
|
if e != 0 {
|
||||||
b.Fatal(root)
|
b.Fatal(root)
|
||||||
}
|
}
|
||||||
|
root.skipAllKey()
|
||||||
|
_, err := root.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
b.SetBytes(int64(len(data)))
|
b.SetBytes(int64(len(data)))
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i:=0; i<b.N; i++ {
|
for i:=0; i<b.N; i++ {
|
||||||
|
|
@ -178,6 +194,10 @@ func BenchmarkEncodeLoad(b *testing.B) {
|
||||||
b.Fatal(root)
|
b.Fatal(root)
|
||||||
}
|
}
|
||||||
root.loadAllKey()
|
root.loadAllKey()
|
||||||
|
_, err := root.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
b.SetBytes(int64(len(data)))
|
b.SetBytes(int64(len(data)))
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i:=0; i<b.N; i++ {
|
for i:=0; i<b.N; i++ {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue