2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-23 18:06:44 +08:00

feat: optimaze ast.Node API as container of generic values (#150)

* opt: only skip one value when call Iterator.HasNext()

* feat: V_NONE supports Set() and Add()

* feat: add node type V_ANY

* feat: ast.Node implements `json.Unmarshaler`

* fmt: use space instead of tab for indent

* feat: node V_ANY cast to Bool()\Int64()\Float64()\String()\Number()\Map()\Array()Interface()

* feat: V_NULL supports Set() and Add()

Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com>
This commit is contained in:
Yi Duan 2021-12-09 15:43:51 +08:00 committed by GitHub
parent 7d3b22100f
commit 8405d84e31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 942 additions and 543 deletions

View file

@ -17,38 +17,45 @@
package ast package ast
import ( import (
`sync` `sync`
`github.com/bytedance/sonic/encoder`
) )
const ( const (
_MaxBuffer = 4 * 1024 // 4KB buffer size _MaxBuffer = 4 * 1024 // 4KB buffer size
) )
const ( const (
bytesNull = "null" bytesNull = "null"
bytesTrue = "true" bytesTrue = "true"
bytesFalse = "false" bytesFalse = "false"
bytesObject = "{}" bytesObject = "{}"
bytesArray = "[]" bytesArray = "[]"
) )
var bytesPool = sync.Pool{} var bytesPool = sync.Pool{}
func (self *Node) MarshalJSON() ([]byte, error) { func (self *Node) MarshalJSON() ([]byte, error) {
buf := newBuffer() buf := newBuffer()
err := self.encode(buf) err := self.encode(buf)
ret := make([]byte, len(*buf)) if err != nil {
copy(ret, *buf) freeBuffer(buf)
freeBuffer(buf) return nil, err
return ret, err }
ret := make([]byte, len(*buf))
copy(ret, *buf)
freeBuffer(buf)
return ret, err
} }
func newBuffer() *[]byte { func newBuffer() *[]byte {
if ret := bytesPool.Get(); ret != nil { if ret := bytesPool.Get(); ret != nil {
return ret.(*[]byte) return ret.(*[]byte)
} else { } else {
buf := make([]byte, 0, _MaxBuffer) buf := make([]byte, 0, _MaxBuffer)
return &buf return &buf
} }
} }
@ -58,130 +65,135 @@ func freeBuffer(buf *[]byte) {
} }
func (self *Node) encode(buf *[]byte) error { func (self *Node) encode(buf *[]byte) error {
if self.IsRaw() { if self.IsRaw() {
return self.encodeRaw(buf) return self.encodeRaw(buf)
} }
switch self.Type() { switch self.Type() {
case V_NONE : return ErrNotExist case V_NONE : return ErrNotExist
case V_ERROR : return self.Check() case V_ERROR : return self.Check()
case V_NULL : return self.encodeNull(buf) case V_NULL : return self.encodeNull(buf)
case V_TRUE : return self.encodeTrue(buf) case V_TRUE : return self.encodeTrue(buf)
case V_FALSE : return self.encodeFalse(buf) case V_FALSE : return self.encodeFalse(buf)
case V_ARRAY : return self.encodeArray(buf) case V_ARRAY : return self.encodeArray(buf)
case V_OBJECT: return self.encodeObject(buf) case V_OBJECT: return self.encodeObject(buf)
case V_STRING: return self.encodeString(buf) case V_STRING: return self.encodeString(buf)
case V_NUMBER: return self.encodeNumber(buf) case V_NUMBER: return self.encodeNumber(buf)
default : return ErrUnsupportType case V_ANY : return self.encodeInterface(buf)
} default : return ErrUnsupportType
}
} }
func (self *Node) encodeRaw(buf *[]byte) error { func (self *Node) encodeRaw(buf *[]byte) error {
raw, err := self.Raw() raw, err := self.Raw()
if err != nil { if err != nil {
return err return err
} }
*buf = append(*buf, raw...) *buf = append(*buf, raw...)
return nil return nil
} }
func (self *Node) encodeNull(buf *[]byte) error { func (self *Node) encodeNull(buf *[]byte) error {
*buf = append(*buf, bytesNull...) *buf = append(*buf, bytesNull...)
return nil return nil
} }
func (self *Node) encodeTrue(buf *[]byte) error { func (self *Node) encodeTrue(buf *[]byte) error {
*buf = append(*buf, bytesTrue...) *buf = append(*buf, bytesTrue...)
return nil return nil
} }
func (self *Node) encodeFalse(buf *[]byte) error { func (self *Node) encodeFalse(buf *[]byte) error {
*buf = append(*buf, bytesFalse...) *buf = append(*buf, bytesFalse...)
return nil return nil
} }
func (self *Node) encodeNumber(buf *[]byte) error { func (self *Node) encodeNumber(buf *[]byte) error {
str := addr2str(self.p, self.v) str := addr2str(self.p, self.v)
*buf = append(*buf, str...) *buf = append(*buf, str...)
return nil return nil
} }
func (self *Node) encodeString(buf *[]byte) error { func (self *Node) encodeString(buf *[]byte) error {
str := addr2str(self.p, self.v) str := addr2str(self.p, self.v)
*buf = append(*buf, '"') *buf = append(*buf, '"')
*buf = append(*buf, str...) *buf = append(*buf, str...)
*buf = append(*buf, '"') *buf = append(*buf, '"')
return nil return nil
} }
func (self *Node) encodeArray(buf *[]byte) error { func (self *Node) encodeArray(buf *[]byte) error {
if self.isLazy() { if self.isLazy() {
if err := self.skipAllIndex(); err != nil { if err := self.skipAllIndex(); err != nil {
return err return err
} }
} }
nb := self.len() nb := self.len()
if nb == 0 { if nb == 0 {
*buf = append(*buf, bytesArray...) *buf = append(*buf, bytesArray...)
return nil return nil
} }
*buf = append(*buf, '[') *buf = append(*buf, '[')
var p = (*Node)(self.p) var p = (*Node)(self.p)
err := p.encode(buf) err := p.encode(buf)
if err != nil { if err != nil {
return err return err
} }
for i := 1; i < nb; i++ { for i := 1; i < nb; i++ {
*buf = append(*buf, ',') *buf = append(*buf, ',')
p = p.unsafe_next() p = p.unsafe_next()
err := p.encode(buf) err := p.encode(buf)
if err != nil { if err != nil {
return err return err
} }
} }
*buf = append(*buf, ']') *buf = append(*buf, ']')
return nil return nil
} }
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...) *buf = append(*buf, self.Key...)
*buf = append(*buf, '"', ':') *buf = append(*buf, '"', ':')
return self.Value.encode(buf) return self.Value.encode(buf)
} }
func (self *Node) encodeObject(buf *[]byte) error { func (self *Node) encodeObject(buf *[]byte) error {
if self.isLazy() { if self.isLazy() {
if err := self.skipAllKey(); err != nil { if err := self.skipAllKey(); err != nil {
return err return err
} }
} }
nb := self.len() nb := self.len()
if nb == 0 { if nb == 0 {
*buf = append(*buf, bytesObject...) *buf = append(*buf, bytesObject...)
return nil return nil
} }
*buf = append(*buf, '{') *buf = append(*buf, '{')
var p = (*Pair)(self.p) var p = (*Pair)(self.p)
err := p.encode(buf) err := p.encode(buf)
if err != nil { if err != nil {
return err return err
} }
for i := 1; i < nb; i++ { for i := 1; i < nb; i++ {
*buf = append(*buf, ',') *buf = append(*buf, ',')
p = p.unsafe_next() p = p.unsafe_next()
err := p.encode(buf) err := p.encode(buf)
if err != nil { if err != nil {
return err return err
} }
} }
*buf = append(*buf, '}') *buf = append(*buf, '}')
return nil return nil
}
func (self *Node) encodeInterface(buf *[]byte) error {
return encoder.EncodeInto(buf, self.packAny(), 0)
} }

View file

@ -17,17 +17,19 @@
package ast package ast
import ( import (
`encoding/json`
`testing`
`runtime` `runtime`
`runtime/debug` `runtime/debug`
`sync` `sync`
`testing`
`github.com/bytedance/sonic/decoder`
`github.com/bytedance/sonic/encoder`
`github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/native/types`
`github.com/stretchr/testify/assert`
) )
func TestGC_Encode(t *testing.T) { func TestGC_Encode(t *testing.T) {
if debugSyncGC { if debugSyncGC {
return return
} }
root, err := NewSearcher(_TwitterJson).GetByPath() root, err := NewSearcher(_TwitterJson).GetByPath()
@ -44,12 +46,12 @@ func TestGC_Encode(t *testing.T) {
for i:=0; i<N; i++ { for i:=0; i<N; i++ {
wg.Add(1) wg.Add(1)
go func (wg *sync.WaitGroup) { go func (wg *sync.WaitGroup) {
defer wg.Done() defer wg.Done()
root, err := NewSearcher(_TwitterJson).GetByPath() root, err := NewSearcher(_TwitterJson).GetByPath()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
root.Load() root.Load()
_, err = root.MarshalJSON() _, err = root.MarshalJSON()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -62,118 +64,126 @@ func TestGC_Encode(t *testing.T) {
} }
func TestEncodeValue(t *testing.T) { func TestEncodeValue(t *testing.T) {
type Case struct { obj := new(_TwitterStruct)
node Node if err := decoder.NewDecoder(_TwitterJson).Decode(obj); err != nil {
exp string t.Fatal(err)
err bool }
} buf, err := encoder.Encode(obj, 0)
input := []Case{ if err != nil {
{NewNull(), "null", false}, t.Fatal(err)
{NewBool(true), "true", false}, }
{NewBool(false), "false", false}, type Case struct {
{NewNumber("0.0"), "0.0", false}, node Node
{NewString(""), `""`, false}, exp string
{NewArray([]Node{}), "[]", false}, err bool
{NewArray([]Node{NewBool(true), NewString("true")}), `[true,"true"]`, false}, }
{NewObject([]Pair{Pair{"a", NewNull()}, Pair{"b", NewNumber("0")}}), `{"a":null,"b":0}`, false}, input := []Case{
{NewObject([]Pair{}), `{}`, false}, {NewNull(), "null", false},
{newRawNode(`[{ }]`, types.V_ARRAY), "[{}]", false}, {NewBool(true), "true", false},
{Node{}, "", true}, {NewBool(false), "false", false},
{Node{t: types.V_EOF}, "", true}, {NewNumber("0.0"), "0.0", false},
} {NewString(""), `""`, false},
for i, c := range input { {NewArray([]Node{}), "[]", false},
buf, err := json.Marshal(&c.node) {NewArray([]Node{NewBool(true), NewString("true")}), `[true,"true"]`, false},
if c.err { {NewObject([]Pair{Pair{"a", NewNull()}, Pair{"b", NewNumber("0")}}), `{"a":null,"b":0}`, false},
if err == nil { {NewObject([]Pair{}), `{}`, false},
t.Fatal(i) {NewBytes([]byte("hello, world")), `"aGVsbG8sIHdvcmxk"`, false},
} {NewAny(obj), string(buf), false},
continue {NewRaw(`[{ }]`), "[{}]", false},
} {Node{}, "", true},
if err != nil { {Node{t: types.ValueType(1)}, "", true},
t.Fatal(i, err) }
} for i, c := range input {
if string(buf) != c.exp { buf, err := encoder.Encode(&c.node, 0)
t.Fatal(i, string(buf)) if c.err {
} if err == nil {
} t.Fatal(i)
}
continue
}
if err != nil {
t.Fatal(i, err)
}
assert.Equal(t, c.exp, string(buf))
}
} }
func TestEncodeNode(t *testing.T) { func TestEncodeNode(t *testing.T) {
data := `{"a":[{},[],-0.1,true,false,null,""],"b":0,"c":true,"d":false,"e":null,"g":""}` data := `{"a":[{},[],-0.1,true,false,null,""],"b":0,"c":true,"d":false,"e":null,"g":""}`
root, e := NewSearcher(data).GetByPath() root, e := NewSearcher(data).GetByPath()
if e != nil { if e != nil {
t.Fatal(root) t.Fatal(root)
} }
ret, err := root.MarshalJSON() ret, err := root.MarshalJSON()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if string(ret) != data { if string(ret) != data {
t.Fatal(string(ret)) t.Fatal(string(ret))
} }
root.skipAllKey() root.skipAllKey()
ret, err = root.MarshalJSON() ret, err = root.MarshalJSON()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if string(ret) != data { if string(ret) != data {
t.Fatal(string(ret)) t.Fatal(string(ret))
} }
root.loadAllKey() root.loadAllKey()
ret, err = root.MarshalJSON() ret, err = root.MarshalJSON()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if string(ret) != data { if string(ret) != data {
t.Fatal(string(ret)) t.Fatal(string(ret))
} }
} }
func BenchmarkEncodeRaw(b *testing.B) { func BenchmarkEncodeRaw(b *testing.B) {
data := _TwitterJson data := _TwitterJson
root, e := NewSearcher(data).GetByPath() root, e := NewSearcher(data).GetByPath()
if e != nil { if e != nil {
b.Fatal(root) b.Fatal(root)
} }
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++ {
_, err := root.MarshalJSON() _, err := root.MarshalJSON()
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
} }
func BenchmarkEncodeSkip(b *testing.B) { func BenchmarkEncodeSkip(b *testing.B) {
data := _TwitterJson data := _TwitterJson
root, e := NewParser(data).Parse() root, e := NewParser(data).Parse()
if e != 0 { if e != 0 {
b.Fatal(root) b.Fatal(root)
} }
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++ {
_, err := root.MarshalJSON() _, err := root.MarshalJSON()
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
} }
func BenchmarkEncodeLoad(b *testing.B) { func BenchmarkEncodeLoad(b *testing.B) {
data := _TwitterJson data := _TwitterJson
root, e := NewParser(data).Parse() root, e := NewParser(data).Parse()
if e != 0 { if e != 0 {
b.Fatal(root) b.Fatal(root)
} }
root.loadAllKey() root.loadAllKey()
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++ {
_, err := root.MarshalJSON() _, err := root.MarshalJSON()
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
} }

View file

@ -16,11 +16,31 @@
package ast package ast
import (
`github.com/bytedance/sonic/internal/native/types`
)
type Pair struct { type Pair struct {
Key string Key string
Value Node Value Node
} }
// Values returns iterator for array's children traversal
func (self *Node) Values() (ListIterator, error) {
if err := self.should(types.V_ARRAY, "an array"); err != nil {
return ListIterator{}, err
}
return ListIterator{Iterator{p: self}}, nil
}
// Properties returns iterator for object's children traversal
func (self *Node) Properties() (ObjectIterator, error) {
if err := self.should(types.V_OBJECT, "an object"); err != nil {
return ObjectIterator{}, err
}
return ObjectIterator{Iterator{p: self}}, nil
}
type Iterator struct { type Iterator struct {
i int i int
p *Node p *Node
@ -34,18 +54,30 @@ func (self *Iterator) Len() int {
return self.p.len() return self.p.len()
} }
// HasNext reports if it is the end of iteration or has error.
func (self *Iterator) HasNext() bool { func (self *Iterator) HasNext() bool {
return self.i < self.p.len() && self.p.Valid() if !self.p.isLazy() {
return self.p.Valid() && self.i < self.p.len()
} else if self.p.t == _V_ARRAY_LAZY {
return self.p.skipNextNode().Valid()
} else if self.p.t == _V_OBJECT_LAZY {
return self.p.skipNextPair().Value.Valid()
}
return false
} }
// ListIterator is specialized iterator for V_ARRAY
type ListIterator struct { type ListIterator struct {
Iterator Iterator
} }
// ObjectIterator is specialized iterator for V_ARRAY
type ObjectIterator struct { type ObjectIterator struct {
Iterator Iterator
} }
// Next scans through children of underlying V_ARRAY,
// copies each child to v, and returns .HasNext().
func (self *ListIterator) Next(v *Node) bool { func (self *ListIterator) Next(v *Node) bool {
if !self.HasNext() { if !self.HasNext() {
return false return false
@ -55,6 +87,8 @@ func (self *ListIterator) Next(v *Node) bool {
} }
} }
// Next scans through children of underlying V_OBJECT,
// copies each child to v, and returns .HasNext().
func (self *ObjectIterator) Next(p *Pair) bool { func (self *ObjectIterator) Next(p *Pair) bool {
if !self.HasNext() { if !self.HasNext() {
return false return false

View file

@ -23,20 +23,20 @@ import (
) )
func getTestIteratorSample() (string, int) { func getTestIteratorSample() (string, int) {
var data []int var data []int
var v1 = "" var v1 = ""
var v2 = "" var v2 = ""
loop := _DEFAULT_NODE_CAP+1 loop := _DEFAULT_NODE_CAP+1
for i:=0;i<loop;i++{ for i:=0;i<loop;i++{
data = append(data, i*i) data = append(data, i*i)
v1 += strconv.Itoa(i) v1 += strconv.Itoa(i)
v2 += `"k`+strconv.Itoa(i)+`":`+strconv.Itoa(i) v2 += `"k`+strconv.Itoa(i)+`":`+strconv.Itoa(i)
if i!=loop-1{ if i!=loop-1{
v1+=`,` v1+=`,`
v2+=`,` v2+=`,`
} }
} }
return `{"array":[`+v1+`], "object":{`+v2+`}}`, loop return `{"array":[`+v1+`], "object":{`+v2+`}}`, loop
} }
func TestRawIterator(t *testing.T) { func TestRawIterator(t *testing.T) {
@ -53,8 +53,8 @@ func TestRawIterator(t *testing.T) {
v := &Node{} v := &Node{}
if !ai.Next(v) { if !ai.Next(v) {
t.Fatalf("no next") t.Fatalf("no next")
} }
x, _ := v.Int64() x, _ := v.Int64()
if i < int64(loop) && x != i { if i < int64(loop) && x != i {
t.Fatalf("exp:%v, got:%v", i, v) t.Fatalf("exp:%v, got:%v", i, v)
} }
@ -63,6 +63,9 @@ func TestRawIterator(t *testing.T) {
} }
i++ i++
} }
if i != int64(loop) {
t.Fatal(i)
}
root, err = NewSearcher(str).GetByPath("object") root, err = NewSearcher(str).GetByPath("object")
if err != nil { if err != nil {
@ -74,10 +77,10 @@ func TestRawIterator(t *testing.T) {
v := &Pair{} v := &Pair{}
if !mi.Next(v) { if !mi.Next(v) {
t.Fatalf("no next") t.Fatalf("no next")
} }
x, _ := v.Value.Int64() x, _ := v.Value.Int64()
if i < int64(loop) &&( x != i ||v.Key != fmt.Sprintf("k%d", i)) { if i < int64(loop) &&( x != i ||v.Key != fmt.Sprintf("k%d", i)) {
vv, _ := v.Value.Interface() vv, _ := v.Value.Interface()
t.Fatalf("exp:%v, got:%v", i, vv) t.Fatalf("exp:%v, got:%v", i, vv)
} }
if i != int64(mi.Pos())-1 || i >= int64(mi.Len()) { if i != int64(mi.Pos())-1 || i >= int64(mi.Len()) {
@ -85,111 +88,120 @@ func TestRawIterator(t *testing.T) {
} }
i++ i++
} }
if i != int64(loop) {
t.Fatal(i)
}
} }
func TestIterator(t *testing.T) { func TestIterator(t *testing.T) {
str, loop := getTestIteratorSample() str, loop := getTestIteratorSample()
fmt.Println(str) fmt.Println(str)
root, err := NewParser(str).Parse() root, err := NewParser(str).Parse()
if err != 0 { if err != 0 {
t.Fatal(err) t.Fatal(err)
} }
ai, _ := root.Get("array").Values() ai, _ := root.Get("array").Values()
i := int64(0) i := int64(0)
for ai.HasNext() { for ai.HasNext() {
v := &Node{} v := &Node{}
if !ai.Next(v) { if !ai.Next(v) {
t.Fatalf("no next") t.Fatalf("no next")
} }
x, _ := v.Int64() x, _ := v.Int64()
if i < int64(loop) && x != i { if i < int64(loop) && x != i {
t.Fatalf("exp:%v, got:%v", i, v) t.Fatalf("exp:%v, got:%v", i, v)
} }
if i != int64(ai.Pos())-1 || i >= int64(ai.Len()) { if i != int64(ai.Pos())-1 || i >= int64(ai.Len()) {
t.Fatal(i) t.Fatal(i)
} }
i++ i++
} }
if i != int64(loop) {
t.Fatal(i)
}
root, err = NewParser(str).Parse() root, err = NewParser(str).Parse()
if err != 0 { if err != 0 {
t.Fatal(err) t.Fatal(err)
} }
mi, _ := root.Get("object").Properties() mi, _ := root.Get("object").Properties()
i = int64(0) i = int64(0)
for mi.HasNext() { for mi.HasNext() {
v := &Pair{} v := &Pair{}
if !mi.Next(v) { if !mi.Next(v) {
t.Fatalf("no next") t.Fatalf("no next")
} }
x, _ := v.Value.Int64() x, _ := v.Value.Int64()
if i < int64(loop) &&( x != i ||v.Key != fmt.Sprintf("k%d", i)) { if i < int64(loop) &&( x != i ||v.Key != fmt.Sprintf("k%d", i)) {
vv, _ := v.Value.Interface() vv, _ := v.Value.Interface()
t.Fatalf("exp:%v, got:%v", i, vv) t.Fatalf("exp:%v, got:%v", i, vv)
} }
if i != int64(mi.Pos())-1 || i >= int64(mi.Len()) { if i != int64(mi.Pos())-1 || i >= int64(mi.Len()) {
t.Fatal(i) t.Fatal(i)
} }
i++ i++
} }
if i != int64(loop) {
t.Fatal(i)
}
} }
func BenchmarkArrays(b *testing.B) { func BenchmarkArrays(b *testing.B) {
for i:=0;i<b.N;i++{ for i:=0;i<b.N;i++{
root,err := NewSearcher(_TwitterJson).GetByPath("statuses",1,"entities","hashtags") root,err := NewSearcher(_TwitterJson).GetByPath("statuses",1,"entities","hashtags")
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
a, _ := root.Array() a, _ := root.Array()
for _,v := range a { for _,v := range a {
_ = v _ = v
} }
} }
} }
func BenchmarkListIterator(b *testing.B) { func BenchmarkListIterator(b *testing.B) {
for i:=0;i<b.N;i++{ for i:=0;i<b.N;i++{
root,err := NewSearcher(_TwitterJson).GetByPath("statuses",1,"entities","hashtags") root,err := NewSearcher(_TwitterJson).GetByPath("statuses",1,"entities","hashtags")
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
it, _ := root.Values() it, _ := root.Values()
for it.HasNext() { for it.HasNext() {
v := &Node{} v := &Node{}
if !it.Next(v) { if !it.Next(v) {
b.Fatalf("no value") b.Fatalf("no value")
} }
} }
} }
} }
func BenchmarkMap(b *testing.B) { func BenchmarkMap(b *testing.B) {
for i:=0;i<b.N;i++{ for i:=0;i<b.N;i++{
root,err := NewSearcher(_TwitterJson).GetByPath("statuses",1, "user") root,err := NewSearcher(_TwitterJson).GetByPath("statuses",1, "user")
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
m, _ := root.Map() m, _ := root.Map()
for k,v := range m { for k,v := range m {
_ = v _ = v
_ = k _ = k
} }
} }
} }
func BenchmarkObjectIterator(b *testing.B) { func BenchmarkObjectIterator(b *testing.B) {
for i:=0;i<b.N;i++{ for i:=0;i<b.N;i++{
root,err := NewSearcher(_TwitterJson).GetByPath("statuses",1, "user") root,err := NewSearcher(_TwitterJson).GetByPath("statuses",1, "user")
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
it, _ := root.Properties() it, _ := root.Properties()
for it.HasNext() { for it.HasNext() {
v := &Pair{} v := &Pair{}
if !it.Next(v) { if !it.Next(v) {
b.Fatalf("no value") b.Fatalf("no value")
} }
} }
} }
} }

View file

@ -17,13 +17,15 @@
package ast package ast
import ( import (
`encoding/json` `encoding/json`
`unsafe` `fmt`
`unsafe`
`github.com/bytedance/sonic/decoder` `github.com/bytedance/sonic/decoder`
`github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt` `github.com/bytedance/sonic/internal/rt`
`github.com/bytedance/sonic/unquote` `github.com/bytedance/sonic/unquote`
`github.com/chenzhuoyu/base64x`
) )
const ( const (
@ -40,6 +42,7 @@ const (
_V_LAZY types.ValueType = 1 << 7 _V_LAZY types.ValueType = 1 << 7
_V_RAW types.ValueType = 1 << 8 _V_RAW types.ValueType = 1 << 8
_V_NUMBER = _V_NODE_BASE + 1 _V_NUMBER = _V_NODE_BASE + 1
_V_ANY = _V_NODE_BASE + 2
_V_ARRAY_LAZY = _V_LAZY | types.V_ARRAY _V_ARRAY_LAZY = _V_LAZY | types.V_ARRAY
_V_OBJECT_LAZY = _V_LAZY | types.V_OBJECT _V_OBJECT_LAZY = _V_LAZY | types.V_OBJECT
_MASK_LAZY = _V_LAZY - 1 _MASK_LAZY = _V_LAZY - 1
@ -56,6 +59,7 @@ const (
V_OBJECT = 6 V_OBJECT = 6
V_STRING = 7 V_STRING = 7
V_NUMBER = int(_V_NUMBER) V_NUMBER = int(_V_NUMBER)
V_ANY = int(_V_ANY)
) )
type Node struct { type Node struct {
@ -64,19 +68,27 @@ type Node struct {
p unsafe.Pointer p unsafe.Pointer
} }
// UnmarshalJSON is just an adapter to json.Unmarshaler.
// If you want better performance, use Searcher.GetByPath() directly
func (self *Node) UnmarshalJSON(data []byte) (err error) {
*self, err = NewSearcher(string(data)).GetByPath()
return
}
/** Node Type Accessor **/ /** Node Type Accessor **/
// Type returns json type represented by the node // Type returns json type represented by the node
// It will be one of belows: // It will be one of belows:
// V_NONE = 0 // V_NONE = 0 (empty node)
// V_ERROR = 1 // V_ERROR = 1 (error node)
// V_NULL = 2 // V_NULL = 2 (json value `null`)
// V_TRUE = 3 // V_TRUE = 3 (json value `true`)
// V_FALSE = 4 // V_FALSE = 4 (json value `false`)
// V_ARRAY = 5 // V_ARRAY = 5 (json value array)
// V_OBJECT = 6 // V_OBJECT = 6 (json value object)
// V_STRING = 7 // V_STRING = 7 (json value string)
// V_NUMBER = 33 // V_NUMBER = 33 (json value number )
// V_ANY = 34 (golang interface{})
func (self Node) Type() int { func (self Node) Type() int {
return int(self.t & _MASK_LAZY & _MASK_RAW) return int(self.t & _MASK_LAZY & _MASK_RAW)
} }
@ -85,25 +97,24 @@ func (self Node) itype() types.ValueType {
return self.t & _MASK_LAZY & _MASK_RAW return self.t & _MASK_LAZY & _MASK_RAW
} }
// Exists returns false only if the node is nil or got by invalid path // Exists returns false only if the self is nil or empty node V_NONE
func (self *Node) Exists() bool { func (self *Node) Exists() bool {
return self != nil && self.t != _V_NONE return self != nil && self.t != _V_NONE
} }
// Valid returns true when the node has any type of V_NULL ~ V_STRING, or V_NUMBER // Valid reports if self is NOT V_ERROR or nil
func (self *Node) Valid() bool { func (self *Node) Valid() bool {
if self == nil { if self == nil {
return false return false
} }
it := self.Type() return self.t != V_ERROR
return it >= V_NULL && it <= V_STRING || it == V_NUMBER
} }
// Check check if the node itself is valid, and return: // Check checks if the node itself is valid, and return:
// - ErrNotFound If the node does not exist // - ErrNotFound If the node is nil
// - Its underlying error If the node is V_ERROR // - Its underlying error If the node is V_ERROR
func (self *Node) Check() error { func (self *Node) Check() error {
if self == nil || self.t == V_NONE { if self == nil {
return ErrNotExist return ErrNotExist
} else if self.t != V_ERROR { } else if self.t != V_ERROR {
return nil return nil
@ -114,9 +125,7 @@ func (self *Node) Check() error {
// Error returns error message if the node is invalid // Error returns error message if the node is invalid
func (self Node) Error() string { func (self Node) Error() string {
if self.t == V_NONE { if self.t != V_ERROR {
return "unsupported type"
} else if self.t != V_ERROR {
return "" return ""
} else { } else {
return *(*string)(self.p) return *(*string)(self.p)
@ -128,17 +137,21 @@ func (self Node) IsRaw() bool {
return self.t&_V_RAW != 0 return self.t&_V_RAW != 0
} }
func (self Node) isLazy() bool { func (self *Node) isLazy() bool {
return self.t&_V_LAZY != 0 return self != nil && self.t&_V_LAZY != 0
}
func (self *Node) isAny() bool {
return self != nil && self.t == _V_ANY
} }
/** Simple Value Methods **/ /** Simple Value Methods **/
// Raw returns underlying json string of an raw node, // Raw returns json representation of the node,
// which usually created by Search() api
func (self *Node) Raw() (string, error) { func (self *Node) Raw() (string, error) {
if !self.IsRaw() { if !self.IsRaw() {
return "", ErrUnsupportType buf, err := self.MarshalJSON()
return rt.Mem2Str(buf), err
} }
return addr2str(self.p, self.v), nil return addr2str(self.p, self.v), nil
} }
@ -155,7 +168,8 @@ func (self *Node) checkRaw() error {
// Bool_E returns bool value represented by this node // Bool_E returns bool value represented by this node
// //
// If node type is not types.V_TRUE or types.V_FALSE, or V_RAW (must be a bool json value), // If node type is not types.V_TRUE or types.V_FALSE,
// V_RAW (must be a bool json value), or V_ANY (must be a bool type)
// it will return error // it will return error
func (self *Node) Bool() (bool, error) { func (self *Node) Bool() (bool, error) {
if err := self.checkRaw(); err != nil { if err := self.checkRaw(); err != nil {
@ -164,6 +178,12 @@ func (self *Node) Bool() (bool, error) {
switch self.t { switch self.t {
case types.V_TRUE : return true , nil case types.V_TRUE : return true , nil
case types.V_FALSE : return false, nil case types.V_FALSE : return false, nil
case _V_ANY :
if v, ok := self.packAny().(bool); ok {
return v, nil
} else {
return false, ErrUnsupportType
}
default : return false, ErrUnsupportType default : return false, ErrUnsupportType
} }
} }
@ -177,6 +197,21 @@ func (self *Node) Int64() (int64, error) {
case _V_NUMBER : return numberToInt64(self) case _V_NUMBER : return numberToInt64(self)
case types.V_TRUE : return 1, nil case types.V_TRUE : return 1, nil
case types.V_FALSE : return 0, nil case types.V_FALSE : return 0, nil
case _V_ANY :
any := self.packAny()
switch v := any.(type) {
case int : return int64(v), nil
case int8 : return int64(v), nil
case int16 : return int64(v), nil
case int32 : return int64(v), nil
case int64 : return int64(v), nil
case uint : return int64(v), nil
case uint8 : return int64(v), nil
case uint16: return int64(v), nil
case uint32: return int64(v), nil
case uint64: return int64(v), nil
default: return 0, ErrUnsupportType
}
default : return 0, ErrUnsupportType default : return 0, ErrUnsupportType
} }
} }
@ -190,6 +225,12 @@ func (self *Node) Number() (json.Number, error) {
case _V_NUMBER : return toNumber(self) , nil case _V_NUMBER : return toNumber(self) , nil
case types.V_TRUE : return json.Number("1"), nil case types.V_TRUE : return json.Number("1"), nil
case types.V_FALSE : return json.Number("0"), nil case types.V_FALSE : return json.Number("0"), nil
case _V_ANY :
if v, ok := self.packAny().(json.Number); ok {
return v, nil
} else {
return json.Number(""), ErrUnsupportType
}
default : return json.Number(""), ErrUnsupportType default : return json.Number(""), ErrUnsupportType
} }
} }
@ -200,6 +241,7 @@ func (self *Node) Number() (json.Number, error) {
// V_TRUE => "true", // V_TRUE => "true",
// V_FALSE => "false", // V_FALSE => "false",
// V_NUMBER => "[0-9\.]*" // V_NUMBER => "[0-9\.]*"
// V_ANY => interface{}.(string)
func (self *Node) String() (string, error) { func (self *Node) String() (string, error) {
if err := self.checkRaw(); err != nil { if err := self.checkRaw(); err != nil {
return "", err return "", err
@ -210,6 +252,12 @@ func (self *Node) String() (string, error) {
case types.V_TRUE : return "true" , nil case types.V_TRUE : return "true" , nil
case types.V_FALSE : return "false", nil case types.V_FALSE : return "false", nil
case types.V_STRING : return addr2str(self.p, self.v), nil case types.V_STRING : return addr2str(self.p, self.v), nil
case _V_ANY :
if v, ok := self.packAny().(string); ok {
return v, nil
} else {
return "", ErrUnsupportType
}
default : return "" , ErrUnsupportType default : return "" , ErrUnsupportType
} }
} }
@ -223,6 +271,13 @@ func (self *Node) Float64() (float64, error) {
case _V_NUMBER : return numberToFloat64(self) case _V_NUMBER : return numberToFloat64(self)
case types.V_TRUE : return 1.0, nil case types.V_TRUE : return 1.0, nil
case types.V_FALSE : return 0.0, nil case types.V_FALSE : return 0.0, nil
case _V_ANY :
any := self.packAny()
switch v := any.(type) {
case float32 : return float64(v), nil
case float64 : return float64(v), nil
default : return 0, ErrUnsupportType
}
default : return 0.0, ErrUnsupportType default : return 0.0, ErrUnsupportType
} }
} }
@ -239,6 +294,8 @@ func (self *Node) Len() (int, error) {
return int(self.v & _LEN_MASK), nil return int(self.v & _LEN_MASK), nil
} else if self.t == types.V_STRING { } else if self.t == types.V_STRING {
return int(self.v), nil return int(self.v), nil
} else if self.t == _V_NONE || self.t == types.V_NULL {
return 0, nil
} else { } else {
return 0, ErrUnsupportType return 0, ErrUnsupportType
} }
@ -255,6 +312,8 @@ func (self *Node) Cap() (int, error) {
} }
if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == _V_ARRAY_LAZY || self.t == _V_OBJECT_LAZY { if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == _V_ARRAY_LAZY || self.t == _V_OBJECT_LAZY {
return int(self.v >> _CAP_BITS), nil return int(self.v >> _CAP_BITS), nil
} else if self.t == _V_NONE || self.t == types.V_NULL {
return 0, nil
} else { } else {
return 0, ErrUnsupportType return 0, ErrUnsupportType
} }
@ -264,9 +323,15 @@ func (self Node) cap() int {
return int(self.v >> _CAP_BITS) return int(self.v >> _CAP_BITS)
} }
// Set sets the node of given key under object parent // Set sets the node of given key under self, and reports if the key has existed.
// If the key doesn't exist, it will be append to the last //
// If self is V_NONE or V_NULL, it becomes V_OBJECT and sets the node at the key.
func (self *Node) Set(key string, node Node) (bool, error) { func (self *Node) Set(key string, node Node) (bool, error) {
if self != nil && (self.t == _V_NONE || self.t == types.V_NULL) {
*self = NewObject([]Pair{{key, node}})
return false, nil
}
if err := node.Check(); err != nil { if err := node.Check(); err != nil {
return false, err return false, err
} }
@ -296,7 +361,12 @@ func (self *Node) Set(key string, node Node) (bool, error) {
return true, nil return true, nil
} }
// Unset remove the node of given key under object parent // SetAny wraps val with V_ANY node, and Set() the node.
func (self *Node) SetAny(key string, val interface{}) (bool, error) {
return self.Set(key, NewAny(val))
}
// Unset remove the node of given key under object parent, and reports if the key has existed.
func (self *Node) Unset(key string) (bool, error) { func (self *Node) Unset(key string) (bool, error) {
self.must(types.V_OBJECT, "an object") self.must(types.V_OBJECT, "an object")
p, i := self.skipKey(key) p, i := self.skipKey(key)
@ -310,9 +380,9 @@ func (self *Node) Unset(key string) (bool, error) {
return true, nil return true, nil
} }
// SetByIndex sets the node of given index // SetByIndex sets the node of given index, and reports if the key has existed.
// //
// The index must within parent array's children // The index must be within self's children.
func (self *Node) SetByIndex(index int, node Node) (bool, error) { func (self *Node) SetByIndex(index int, node Node) (bool, error) {
if err := node.Check(); err != nil { if err := node.Check(); err != nil {
return false, err return false, err
@ -329,6 +399,11 @@ func (self *Node) SetByIndex(index int, node Node) (bool, error) {
return true, nil return true, nil
} }
// SetAny wraps val with V_ANY node, and SetByIndex() the node.
func (self *Node) SetAnyByIndex(index int, val interface{}) (bool, error) {
return self.SetByIndex(index, NewAny(val))
}
// UnsetByIndex remove the node of given index // UnsetByIndex remove the node of given index
func (self *Node) UnsetByIndex(index int) (bool, error) { func (self *Node) UnsetByIndex(index int) (bool, error) {
var p *Node var p *Node
@ -341,7 +416,7 @@ func (self *Node) UnsetByIndex(index int) (bool, error) {
return false, ErrNotExist return false, ErrNotExist
} }
p = &pr.Value p = &pr.Value
}else{ } else {
return false, ErrUnsupportType return false, ErrUnsupportType
} }
@ -357,8 +432,15 @@ func (self *Node) UnsetByIndex(index int) (bool, error) {
return true, nil return true, nil
} }
// Add appends the given node under array node // Add appends the given node under self.
//
// If self is V_NONE or V_NULL, it becomes V_ARRAY and sets the node at index 0.
func (self *Node) Add(node Node) error { func (self *Node) Add(node Node) error {
if self != nil && (self.t == _V_NONE || self.t == types.V_NULL) {
*self = NewArray([]Node{node})
return nil
}
if err := self.should(types.V_ARRAY, "an array"); err != nil { if err := self.should(types.V_ARRAY, "an array"); err != nil {
return err return err
} }
@ -379,6 +461,11 @@ func (self *Node) Add(node Node) error {
return nil return nil
} }
// SetAny wraps val with V_ANY node, and Add() the node.
func (self *Node) AddAny(val interface{}) error {
return self.Add(NewAny(val))
}
// GetByPath load given path on demands, // GetByPath load given path on demands,
// which only ensure nodes before this path got parsed // which only ensure nodes before this path got parsed
func (self *Node) GetByPath(path ...interface{}) *Node { func (self *Node) GetByPath(path ...interface{}) *Node {
@ -428,12 +515,12 @@ func (self *Node) Index(idx int) *Node {
}else if it == types.V_OBJECT { }else if it == types.V_OBJECT {
pr := self.skipIndexPair(idx) pr := self.skipIndexPair(idx)
if pr == nil { if pr == nil {
return nodeNotExist return newError(_ERR_NOT_FOUND, "value not exists")
} }
return &pr.Value return &pr.Value
}else{ } else {
return nodeUnsupportType return newError(_ERR_UNSUPPORT_TYPE, fmt.Sprintf("unsupported type: %v", self.itype()))
} }
} }
@ -461,32 +548,18 @@ func (self *Node) IndexOrGet(idx int, key string) *Node {
return n return n
} }
// Values returns iterator for array's children traversal
func (self *Node) Values() (ListIterator, error) {
if err := self.should(types.V_ARRAY, "an array"); err != nil {
return ListIterator{}, err
}
if err := self.skipAllIndex(); err != nil {
return ListIterator{}, err
}
return ListIterator{Iterator{p: self}}, nil
}
// Properties returns iterator for object's children traversal
func (self *Node) Properties() (ObjectIterator, error) {
if err := self.should(types.V_OBJECT, "an object"); err != nil {
return ObjectIterator{}, err
}
if err := self.skipAllKey(); err != nil {
return ObjectIterator{}, err
}
return ObjectIterator{Iterator{p: self}}, nil
}
/** Generic Value Converters **/ /** Generic Value Converters **/
// Map loads all keys of an object node // Map loads all keys of an object node
func (self *Node) Map() (map[string]interface{}, error) { func (self *Node) Map() (map[string]interface{}, error) {
if self.isAny() {
any := self.packAny()
if v, ok := any.(map[string]interface{}); ok {
return v, nil
} else {
return nil, ErrUnsupportType
}
}
if err := self.should(types.V_OBJECT, "an object"); err != nil { if err := self.should(types.V_OBJECT, "an object"); err != nil {
return nil, err return nil, err
} }
@ -498,6 +571,14 @@ func (self *Node) Map() (map[string]interface{}, error) {
// MapUseNumber loads all keys of an object node, with numeric nodes casted to json.Number // MapUseNumber loads all keys of an object node, with numeric nodes casted to json.Number
func (self *Node) MapUseNumber() (map[string]interface{}, error) { func (self *Node) MapUseNumber() (map[string]interface{}, error) {
if self.isAny() {
any := self.packAny()
if v, ok := any.(map[string]interface{}); ok {
return v, nil
} else {
return nil, ErrUnsupportType
}
}
if err := self.should(types.V_OBJECT, "an object"); err != nil { if err := self.should(types.V_OBJECT, "an object"); err != nil {
return nil, err return nil, err
} }
@ -510,6 +591,14 @@ func (self *Node) MapUseNumber() (map[string]interface{}, error) {
// MapUseNode scans both parsed and non-parsed chidren nodes, // MapUseNode scans both parsed and non-parsed chidren nodes,
// and map them by their keys // and map them by their keys
func (self *Node) MapUseNode() (map[string]Node, error) { func (self *Node) MapUseNode() (map[string]Node, error) {
if self.isAny() {
any := self.packAny()
if v, ok := any.(map[string]Node); ok {
return v, nil
} else {
return nil, ErrUnsupportType
}
}
if err := self.should(types.V_OBJECT, "an object"); err != nil { if err := self.should(types.V_OBJECT, "an object"); err != nil {
return nil, err return nil, err
} }
@ -534,6 +623,14 @@ func (self *Node) UnsafeMap() ([]Pair, error) {
// Array loads all indexes of an array node // Array loads all indexes of an array node
func (self *Node) Array() ([]interface{}, error) { func (self *Node) Array() ([]interface{}, error) {
if self.isAny() {
any := self.packAny()
if v, ok := any.([]interface{}); ok {
return v, nil
} else {
return nil, ErrUnsupportType
}
}
if err := self.should(types.V_ARRAY, "an array"); err != nil { if err := self.should(types.V_ARRAY, "an array"); err != nil {
return nil, err return nil, err
} }
@ -545,6 +642,14 @@ func (self *Node) Array() ([]interface{}, error) {
// ArrayUseNumber loads all indexes of an array node, with numeric nodes casted to json.Number // ArrayUseNumber loads all indexes of an array node, with numeric nodes casted to json.Number
func (self *Node) ArrayUseNumber() ([]interface{}, error) { func (self *Node) ArrayUseNumber() ([]interface{}, error) {
if self.isAny() {
any := self.packAny()
if v, ok := any.([]interface{}); ok {
return v, nil
} else {
return nil, ErrUnsupportType
}
}
if err := self.should(types.V_ARRAY, "an array"); err != nil { if err := self.should(types.V_ARRAY, "an array"); err != nil {
return nil, err return nil, err
} }
@ -557,6 +662,14 @@ func (self *Node) ArrayUseNumber() ([]interface{}, error) {
// ArrayUseNode copys both parsed and non-parsed chidren nodes, // ArrayUseNode copys both parsed and non-parsed chidren nodes,
// and indexes them by original order // and indexes them by original order
func (self *Node) ArrayUseNode() ([]Node, error) { func (self *Node) ArrayUseNode() ([]Node, error) {
if self.isAny() {
any := self.packAny()
if v, ok := any.([]Node); ok {
return v, nil
} else {
return nil, ErrUnsupportType
}
}
if err := self.should(types.V_ARRAY, "an array"); err != nil { if err := self.should(types.V_ARRAY, "an array"); err != nil {
return nil, err return nil, err
} }
@ -610,10 +723,20 @@ func (self *Node) Interface() (interface{}, error) {
return nil, err return nil, err
} }
return self.toGenericObject() return self.toGenericObject()
case _V_ANY:
switch v := self.packAny().(type) {
case Node : return v.Interface()
case *Node: return v.Interface()
default : return v, nil
}
default : return nil, ErrUnsupportType default : return nil, ErrUnsupportType
} }
} }
func (self *Node) packAny() interface{} {
return *(*interface{})(self.p)
}
// InterfaceUseNumber works same with Interface() // InterfaceUseNumber works same with Interface()
// except numberic nodes are casted to json.Number // except numberic nodes are casted to json.Number
func (self *Node) InterfaceUseNumber() (interface{}, error) { func (self *Node) InterfaceUseNumber() (interface{}, error) {
@ -639,6 +762,7 @@ func (self *Node) InterfaceUseNumber() (interface{}, error) {
return nil, err return nil, err
} }
return self.toGenericObjectUseNumber() return self.toGenericObjectUseNumber()
case _V_ANY : return self.packAny(), nil
default : return nil, ErrUnsupportType default : return nil, ErrUnsupportType
} }
} }
@ -662,66 +786,66 @@ func (self *Node) InterfaceUseNode() (interface{}, error) {
return nil, err return nil, err
} }
return self.toGenericObjectUseNode() return self.toGenericObjectUseNode()
default : return *self, nil default : return *self, self.Check()
} }
} }
// LoadAll loads all the node's children and children's children as parsed. // LoadAll loads all the node's children and children's children as parsed.
// After calling it, the node can be safely used on concurrency // After calling it, the node can be safely used on concurrency
func (self *Node) LoadAll() error { func (self *Node) LoadAll() error {
if self.IsRaw() { if self.IsRaw() {
self.parseRaw(true) self.parseRaw(true)
return self.Check() return self.Check()
} }
switch self.itype() { switch self.itype() {
case types.V_ARRAY: case types.V_ARRAY:
e := self.len() e := self.len()
if err := self.loadAllIndex(); err != nil { if err := self.loadAllIndex(); err != nil {
return err return err
} }
for i := 0; i < e; i++ { for i := 0; i < e; i++ {
n := self.nodeAt(i) n := self.nodeAt(i)
n.parseRaw(true) n.parseRaw(true)
if err := n.Check(); err != nil { if err := n.Check(); err != nil {
return err return err
} }
} }
return nil return nil
case types.V_OBJECT: case types.V_OBJECT:
e := self.len() e := self.len()
if err := self.loadAllKey(); err != nil { if err := self.loadAllKey(); err != nil {
return err return err
} }
for i := 0; i < e; i++ { for i := 0; i < e; i++ {
n := self.pairAt(i) n := self.pairAt(i)
n.Value.parseRaw(true) n.Value.parseRaw(true)
if err := n.Value.Check(); err != nil { if err := n.Value.Check(); err != nil {
return err return err
} }
} }
return nil return nil
default: default:
return self.Check() return self.Check()
} }
} }
// Load loads the node's children as parsed. // Load loads the node's children as parsed.
// After calling it, only the node itself can be used on concurrency (not include its children) // After calling it, only the node itself can be used on concurrency (not include its children)
func (self *Node) Load() error { func (self *Node) Load() error {
if self.IsRaw() { if self.IsRaw() {
self.parseRaw(false) self.parseRaw(false)
return self.Load() return self.Load()
} }
switch self.t { switch self.t {
case _V_ARRAY_LAZY: case _V_ARRAY_LAZY:
return self.skipAllIndex() return self.skipAllIndex()
case _V_OBJECT_LAZY: case _V_OBJECT_LAZY:
return self.skipAllKey() return self.skipAllKey()
default: default:
return self.Check() return self.Check()
} }
} }
/**---------------------------------- Internal Helper Methods ----------------------------------**/ /**---------------------------------- Internal Helper Methods ----------------------------------**/
@ -859,7 +983,7 @@ func (self *Node) skipNextNode() *Node {
/* skip the value */ /* skip the value */
if start, err := parser.skip(); err != 0 { if start, err := parser.skip(); err != 0 {
return newSyntaxError(parser.syntaxError(err)) return newSyntaxError(parser.syntaxError(err))
}else{ } else {
t := switchRawType(parser.s[start]) t := switchRawType(parser.s[start])
if t == _V_NONE { if t == _V_NONE {
return newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR)) return newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))
@ -942,7 +1066,7 @@ func (self *Node) skipNextPair() (*Pair) {
/* skip the value */ /* skip the value */
if start, err := parser.skip(); err != 0 { if start, err := parser.skip(); err != 0 {
return &Pair{key, *newSyntaxError(parser.syntaxError(err))} return &Pair{key, *newSyntaxError(parser.syntaxError(err))}
}else{ } else {
t := switchRawType(parser.s[start]) t := switchRawType(parser.s[start])
if t == _V_NONE { if t == _V_NONE {
return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))} return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))}
@ -1299,6 +1423,41 @@ var (
emptyObjectNode = Node{t: types.V_OBJECT} emptyObjectNode = Node{t: types.V_OBJECT}
) )
// NewRaw creates a node of raw json, and decides its type by first char.
func NewRaw(json string) Node {
if json == "" {
panic("empty json string")
}
it := switchRawType(json[0])
return newRawNode(json, it)
}
// NewAny creates a node of type V_ANY if any's type isn't Node or *Node,
// which stores interface{} and can be only used for `.Interface()`\`.MarshalJSON()`.
func NewAny(any interface{}) Node {
switch n := any.(type) {
case Node:
return n
case *Node:
return *n
default:
return Node{
t: _V_ANY,
v: 0,
p: unsafe.Pointer(&any),
}
}
}
// NewBytes encodes given src with Base64 (RFC 4648), and creates a node of type V_STRING.
func NewBytes(src []byte) Node {
if len(src) == 0 {
panic("empty src bytes")
}
out := base64x.StdEncoding.EncodeToString(src)
return NewString(out)
}
// NewNull creates a node of type V_NULL // NewNull creates a node of type V_NULL
func NewNull() Node { func NewNull() Node {
return Node{ return Node{
@ -1520,7 +1679,7 @@ func unwrapError(err error) *Node {
return se return se
}else if sse, ok := err.(Node); ok { }else if sse, ok := err.(Node); ok {
return &sse return &sse
}else{ } else {
msg := err.Error() msg := err.Error()
return &Node{ return &Node{
t: V_ERROR, t: V_ERROR,

View file

@ -20,21 +20,47 @@ import (
`encoding/json` `encoding/json`
`fmt` `fmt`
`reflect` `reflect`
`runtime`
`runtime/debug`
`strconv` `strconv`
`testing` `testing`
`github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
`github.com/stretchr/testify/assert` `github.com/stretchr/testify/assert`
) )
//go:noinline
func stackObj() interface{} {
var a int = 1
return rt.UnpackEface(a).Pack()
}
func TestStackAny(t *testing.T) {
var obj = stackObj()
any := NewAny(obj)
fmt.Printf("any: %#v\n", any)
runtime.GC()
debug.FreeOSMemory()
println("finish GC")
buf, err := any.MarshalJSON()
println("finish marshal")
if err != nil {
t.Fatal(err)
}
if string(buf) != `1` {
t.Fatal(string(buf))
}
}
func TestLoadAll(t *testing.T) { func TestLoadAll(t *testing.T) {
e := Node{} e := Node{}
err := e.Load() err := e.Load()
if err != ErrNotExist { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
err = e.LoadAll() err = e.LoadAll()
if err != ErrNotExist { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -151,39 +177,96 @@ func TestTypeCast(t *testing.T) {
exp interface{} exp interface{}
err error err error
} }
a1 := NewAny(1)
lazyArray, _ := NewParser("[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]").Parse() lazyArray, _ := NewParser("[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]").Parse()
lazyObject, _ := NewParser(`{"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16}`).Parse() lazyObject, _ := NewParser(`{"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16}`).Parse()
var cases = []tcase{ var cases = []tcase{
{"Raw", Node{}, "", ErrUnsupportType}, {"Interface", Node{}, interface{}(nil), ErrUnsupportType},
{"Raw", newRawNode("[ ]", types.V_ARRAY), "[ ]", nil}, {"Interface", NewAny(NewNumber("1")), float64(1), nil},
{"Bool", Node{}, false, ErrNotExist}, {"Interface", NewAny(int64(1)), int64(1), nil},
{"Bool", newRawNode("true", types.V_TRUE), true, nil}, {"Interface", NewNumber("1"), float64(1), nil},
{"Bool", newRawNode("false", types.V_FALSE), false, nil}, {"InterfaceUseNode", Node{}, Node{}, nil},
{"Int64", Node{}, int64(0), ErrNotExist}, {"InterfaceUseNode", a1, a1, nil},
{"Int64", newRawNode("0", _V_NUMBER), int64(0), nil}, {"InterfaceUseNode", NewNumber("1"), NewNumber("1"), nil},
{"Float64", Node{}, float64(0), ErrNotExist}, {"InterfaceUseNumber", Node{}, interface{}(nil), ErrUnsupportType},
{"Float64", newRawNode("0.0", _V_NUMBER), float64(0.0), nil}, {"InterfaceUseNumber", NewAny(1), 1, nil},
{"Number", Node{}, json.Number(""), ErrNotExist}, {"InterfaceUseNumber", NewNumber("1"), json.Number("1"), nil},
{"Number", newRawNode("0.0", _V_NUMBER), json.Number("0.0"), nil}, {"Map", Node{}, map[string]interface{}(nil), ErrUnsupportType},
{"Number", newRawNode("true", types.V_TRUE), json.Number("1"), nil}, {"Map", NewAny(map[string]Node{"a":NewNumber("1")}), map[string]interface{}(nil), ErrUnsupportType},
{"Number", newRawNode("false", types.V_FALSE), json.Number("0"), nil}, {"Map", NewAny(map[string]interface{}{"a":1}), map[string]interface{}{"a":1}, nil},
{"String", Node{}, "", ErrNotExist}, {"Map", NewObject([]Pair{{"a",NewNumber("1")}}), map[string]interface{}{"a":float64(1.0)}, nil},
{"String", newRawNode(`""`, types.V_STRING), ``, nil}, {"MapUseNode", Node{}, map[string]Node(nil), ErrUnsupportType},
{"String", newRawNode(`0.0`, _V_NUMBER), "0.0", nil}, {"MapUseNode", NewAny(map[string]interface{}{"a":1}), map[string]Node(nil), ErrUnsupportType},
{"String", newRawNode(`null`, types.V_NULL), "null", nil}, {"MapUseNode", NewAny(map[string]Node{"a":NewNumber("1")}), map[string]Node{"a":NewNumber("1")}, nil},
{"String", newRawNode(`true`, types.V_TRUE), "true", nil}, {"MapUseNode", NewObject([]Pair{{"a",NewNumber("1")}}), map[string]Node{"a":NewNumber("1")}, nil},
{"String", newRawNode(`false`, types.V_FALSE), "false", nil}, {"MapUseNumber", Node{}, map[string]interface{}(nil), ErrUnsupportType},
{"Len", NewNull(), 0, ErrUnsupportType}, {"MapUseNumber", NewAny(map[string]interface{}{"a":1}), map[string]interface{}{"a":1}, nil},
{"Len", newRawNode(`"1"`, types.V_STRING), 1, nil}, {"MapUseNumber", NewObject([]Pair{{"a",NewNumber("1")}}), map[string]interface{}{"a":json.Number("1")}, nil},
{"Len", newRawNode(`[1]`, types.V_ARRAY), 0, nil}, {"Array", Node{}, []interface{}(nil), ErrUnsupportType},
{"Array", NewAny([]interface{}{1}), []interface{}{1}, nil},
{"Array", NewArray([]Node{NewNumber("1")}), []interface{}{float64(1.0)}, nil},
{"ArrayUseNode", Node{}, []Node(nil), ErrUnsupportType},
{"ArrayUseNode", NewAny([]interface{}{1}), []Node(nil), ErrUnsupportType},
{"ArrayUseNode", NewAny([]Node{NewNumber("1")}), []Node{NewNumber("1")}, nil},
{"ArrayUseNode", NewArray([]Node{NewNumber("1")}), []Node{NewNumber("1")}, nil},
{"ArrayUseNumber", Node{}, []interface{}(nil), ErrUnsupportType},
{"ArrayUseNumber", NewAny([]interface{}{1}), []interface{}{1}, nil},
{"ArrayUseNumber", NewAny([]Node{NewNumber("1")}), []interface{}(nil), ErrUnsupportType},
{"ArrayUseNumber", NewArray([]Node{NewNumber("1")}), []interface{}{json.Number("1")}, nil},
{"Raw", Node{}, "", ErrNotExist},
{"Raw", NewAny(""), `""`, nil},
{"Raw", NewRaw("[ ]"), "[ ]", nil},
{"Raw", NewBool(true), "true", nil},
{"Raw", NewNumber("-0.0"), "-0.0", nil},
{"Raw", NewString(""), `""`, nil},
{"Raw", NewBytes([]byte("hello, world")), `"aGVsbG8sIHdvcmxk"`, nil},
{"Bool", Node{}, false, ErrUnsupportType},
{"Bool", NewAny(true), true, nil},
{"Bool", NewAny(false), false, nil},
{"Bool", NewRaw("true"), true, nil},
{"Bool", NewRaw("false"), false, nil},
{"Int64", NewAny(int(0)), int64(0), nil},
{"Int64", NewAny(int8(0)), int64(0), nil},
{"Int64", NewAny(int16(0)), int64(0), nil},
{"Int64", NewAny(int32(0)), int64(0), nil},
{"Int64", NewAny(int64(0)), int64(0), nil},
{"Int64", NewAny(uint(0)), int64(0), nil},
{"Int64", NewAny(uint8(0)), int64(0), nil},
{"Int64", NewAny(uint32(0)), int64(0), nil},
{"Int64", NewAny(uint64(0)), int64(0), nil},
{"Int64", Node{}, int64(0), ErrUnsupportType},
{"Int64", NewRaw("0"), int64(0), nil},
{"Float64", Node{}, float64(0), ErrUnsupportType},
{"Float64", NewAny(float32(0)), float64(0), nil},
{"Float64", NewAny(float64(0)), float64(0), nil},
{"Float64", NewRaw("0.0"), float64(0.0), nil},
{"Number", Node{}, json.Number(""), ErrUnsupportType},
{"Number", NewAny(json.Number("0")), json.Number("0"), nil},
{"Number", NewRaw("0.0"), json.Number("0.0"), nil},
{"Number", NewRaw("true"), json.Number("1"), nil},
{"Number", NewRaw("false"), json.Number("0"), nil},
{"String", Node{}, "", ErrUnsupportType},
{"String", NewAny(""), "", nil},
{"String", NewRaw(`""`), ``, nil},
{"String", NewRaw(`0.0`), "0.0", nil},
{"String", NewRaw(`null`), "null", nil},
{"String", NewRaw(`true`), "true", nil},
{"String", NewRaw(`false`), "false", nil},
{"Len", Node{}, 0, nil},
{"Len", NewAny(0), 0, ErrUnsupportType},
{"Len", NewNull(), 0, nil},
{"Len", NewRaw(`"1"`), 1, nil},
{"Len", NewRaw(`[1]`), 0, nil},
{"Len", NewArray([]Node{NewNull()}), 1, nil}, {"Len", NewArray([]Node{NewNull()}), 1, nil},
{"Len", lazyArray, 0, nil}, {"Len", lazyArray, 0, nil},
{"Len", newRawNode(`{"a":1}`, types.V_OBJECT), 0, nil}, {"Len", NewRaw(`{"a":1}`), 0, nil},
{"Len", lazyObject, 0, nil}, {"Len", lazyObject, 0, nil},
{"Cap", NewNull(), 0, ErrUnsupportType}, {"Cap", Node{}, 0, nil},
{"Cap", newRawNode(`[1]`, types.V_ARRAY), _DEFAULT_NODE_CAP, nil}, {"Cap", NewAny(0), 0, ErrUnsupportType},
{"Cap", NewNull(), 0, nil},
{"Cap", NewRaw(`[1]`), _DEFAULT_NODE_CAP, nil},
{"Cap", NewObject([]Pair{{"",NewNull()}}), 1, nil}, {"Cap", NewObject([]Pair{{"",NewNull()}}), 1, nil},
{"Cap", newRawNode(`{"a":1}`, types.V_OBJECT), _DEFAULT_NODE_CAP, nil}, {"Cap", NewRaw(`{"a":1}`), _DEFAULT_NODE_CAP, nil},
} }
lazyArray.skipAllIndex() lazyArray.skipAllIndex()
lazyObject.skipAllKey() lazyObject.skipAllKey()
@ -195,15 +278,15 @@ func TestTypeCast(t *testing.T) {
) )
for i, c := range cases { for i, c := range cases {
fmt.Println(c) fmt.Println(i, c)
rt := reflect.ValueOf(&c.node) rt := reflect.ValueOf(&c.node)
m := rt.MethodByName(c.method) m := rt.MethodByName(c.method)
rets := m.Call([]reflect.Value{}) rets := m.Call([]reflect.Value{})
if len(rets) != 2 { if len(rets) != 2 {
t.Fatal(i, rets) t.Fatal(i, rets)
} }
if rets[0].Interface() != c.exp { if !reflect.DeepEqual(rets[0].Interface(), c.exp) {
t.Fatal(i, rets[0].Interface()) t.Fatal(i, rets[0].Interface(), c.exp)
} }
if rets[1].Interface() != c.err { if rets[1].Interface() != c.err {
t.Fatal(i, rets[1].Interface()) t.Fatal(i, rets[1].Interface())
@ -212,6 +295,11 @@ func TestTypeCast(t *testing.T) {
} }
func TestCheckError(t *testing.T) { func TestCheckError(t *testing.T) {
empty := Node{}
if !empty.Valid() || empty.Check() != nil || empty.Error() != "" {
t.Fatal()
}
n := newRawNode("[hello]", types.V_ARRAY) n := newRawNode("[hello]", types.V_ARRAY)
n.parseRaw(false) n.parseRaw(false)
if n.Check() != nil { if n.Check() != nil {
@ -680,6 +768,56 @@ func TestNodeGetByPath(t *testing.T) {
} }
func TestNodeSet(t *testing.T) { func TestNodeSet(t *testing.T) {
empty := Node{}
err := empty.Add(Node{})
if err != nil {
t.Fatal(err)
}
empty2 := empty.Index(0)
if empty2.Check() != nil {
t.Fatal(err)
}
exist, err := empty2.SetByIndex(1, Node{})
if exist || err == nil {
t.Fatal(exist, err)
}
empty3 := empty.Index(0)
if empty3.Check() != nil {
t.Fatal(err)
}
exist, err = empty3.Set("a", NewNumber("-1"))
if exist || err != nil {
t.Fatal(exist, err)
}
if n, e := empty.Index(0).Get("a").Int64(); e != nil || n != -1 {
t.Fatal(n, e)
}
empty = NewNull()
err = empty.Add(NewNull())
if err != nil {
t.Fatal(err)
}
empty2 = empty.Index(0)
if empty2.Check() != nil {
t.Fatal(err)
}
exist, err = empty2.SetByIndex(1, NewNull())
if exist || err == nil {
t.Fatal(exist, err)
}
empty3 = empty.Index(0)
if empty3.Check() != nil {
t.Fatal(err)
}
exist, err = empty3.Set("a", NewNumber("-1"))
if exist || err != nil {
t.Fatal(exist, err)
}
if n, e := empty.Index(0).Get("a").Int64(); e != nil || n != -1 {
t.Fatal(n, e)
}
root, derr := NewParser(_TwitterJson).Parse() root, derr := NewParser(_TwitterJson).Parse()
if derr != 0 { if derr != 0 {
t.Fatalf("decode failed: %v", derr.Error()) t.Fatalf("decode failed: %v", derr.Error())
@ -709,6 +847,43 @@ func TestNodeSet(t *testing.T) {
} }
} }
func TestNodeAny(t *testing.T) {
empty := Node{}
_,err := empty.SetAny("any", map[string]interface{}{"a": []int{0}})
if err != nil {
t.Fatal(err)
}
if m, err := empty.Get("any").Interface(); err != nil {
t.Fatal(err)
} else if v, ok := m.(map[string]interface{}); !ok {
t.Fatal(v)
}
if buf, err := empty.MarshalJSON(); err != nil {
t.Fatal(err)
} else if string(buf) != `{"any":{"a":[0]}}` {
t.Fatal(string(buf))
}
if _, err := empty.Set("any2", Node{}); err != nil {
t.Fatal(err)
}
if err := empty.Get("any2").AddAny(nil); err != nil {
t.Fatal(err)
}
if buf, err := empty.MarshalJSON(); err != nil {
t.Fatal(err)
} else if string(buf) != `{"any":{"a":[0]},"any2":[null]}` {
t.Fatal(string(buf))
}
if _, err := empty.Get("any2").SetAnyByIndex(0, NewNumber("-0.0")); err != nil {
t.Fatal(err)
}
if buf, err := empty.MarshalJSON(); err != nil {
t.Fatal(err)
} else if string(buf) != `{"any":{"a":[0]},"any2":[-0.0]}` {
t.Fatal(string(buf))
}
}
func TestNodeSetByIndex(t *testing.T) { func TestNodeSetByIndex(t *testing.T) {
root, derr := NewParser(_TwitterJson).Parse() root, derr := NewParser(_TwitterJson).Parse()
if derr != 0 { if derr != 0 {

View file

@ -17,15 +17,15 @@
package ast package ast
import ( import (
`fmt` `fmt`
`sync` `sync`
`unsafe` `unsafe`
`github.com/bytedance/sonic/decoder` `github.com/bytedance/sonic/decoder`
`github.com/bytedance/sonic/internal/native` `github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt` `github.com/bytedance/sonic/internal/rt`
`github.com/bytedance/sonic/unquote` `github.com/bytedance/sonic/unquote`
) )
const _DEFAULT_NODE_CAP int = 16 const _DEFAULT_NODE_CAP int = 16
@ -36,11 +36,8 @@ const (
) )
var ( var (
nodeNotExist = newError(_ERR_NOT_FOUND, "value not exists") ErrNotExist error = newError(_ERR_NOT_FOUND, "value not exists")
nodeUnsupportType = newError(_ERR_UNSUPPORT_TYPE, "unsupported type") ErrUnsupportType error = newError(_ERR_UNSUPPORT_TYPE, "unsupported type")
ErrNotExist error = nodeNotExist
ErrUnsupportType error = nodeUnsupportType
) )
type Parser struct { type Parser struct {

View file

@ -22,7 +22,7 @@ import (
`runtime/debug` `runtime/debug`
`sync` `sync`
`fmt` `fmt`
`math` `math`
`strconv` `strconv`
`github.com/tidwall/sjson` `github.com/tidwall/sjson`
@ -277,83 +277,83 @@ func BenchmarkGetOne_Parallel_Sonic(b *testing.B) {
} }
func BenchmarkSetOne_Sonic(b *testing.B) { func BenchmarkSetOne_Sonic(b *testing.B) {
node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3) node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
n := NewNumber(strconv.Itoa(math.MaxInt32)) n := NewNumber(strconv.Itoa(math.MaxInt32))
_, err = node.Set("id", n) _, err = node.Set("id", n)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
b.SetBytes(int64(len(_TwitterJson))) b.SetBytes(int64(len(_TwitterJson)))
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
node, _ := NewSearcher(_TwitterJson).GetByPath("statuses", 3) node, _ := NewSearcher(_TwitterJson).GetByPath("statuses", 3)
_, _ = node.Set("id", n) _, _ = node.Set("id", n)
} }
} }
func BenchmarkSetOne_Sjson(b *testing.B) { func BenchmarkSetOne_Sjson(b *testing.B) {
path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id") path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id")
_, err := sjson.Set(_TwitterJson, path, math.MaxInt32) _, err := sjson.Set(_TwitterJson, path, math.MaxInt32)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
b.SetBytes(int64(len(_TwitterJson))) b.SetBytes(int64(len(_TwitterJson)))
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
sjson.Set(_TwitterJson, path, math.MaxInt32) sjson.Set(_TwitterJson, path, math.MaxInt32)
} }
} }
func BenchmarkSetOne_Jsoniter(b *testing.B) { func BenchmarkSetOne_Jsoniter(b *testing.B) {
data := []byte(_TwitterJson) data := []byte(_TwitterJson)
node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{})
if !ok { if !ok {
b.Fatal(node) b.Fatal(node)
} }
b.SetBytes(int64(len(data))) b.SetBytes(int64(len(data)))
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
node, _ := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) node, _ := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{})
node["id"] = math.MaxInt32 node["id"] = math.MaxInt32
} }
} }
func BenchmarkSetOne_Parallel_Sonic(b *testing.B) { func BenchmarkSetOne_Parallel_Sonic(b *testing.B) {
node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3) node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
n := NewNumber(strconv.Itoa(math.MaxInt32)) n := NewNumber(strconv.Itoa(math.MaxInt32))
_, err = node.Set("id", n) _, err = node.Set("id", n)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
b.SetBytes(int64(len(_TwitterJson))) b.SetBytes(int64(len(_TwitterJson)))
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
for pb.Next() { for pb.Next() {
node, _ := NewSearcher(_TwitterJson).GetByPath("statuses", 3) node, _ := NewSearcher(_TwitterJson).GetByPath("statuses", 3)
_, _ = node.Set("id", n) _, _ = node.Set("id", n)
} }
}) })
} }
func BenchmarkSetOne_Parallel_Sjson(b *testing.B) { func BenchmarkSetOne_Parallel_Sjson(b *testing.B) {
path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id") path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id")
_, err := sjson.Set(_TwitterJson, path, math.MaxInt32) _, err := sjson.Set(_TwitterJson, path, math.MaxInt32)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
b.SetBytes(int64(len(_TwitterJson))) b.SetBytes(int64(len(_TwitterJson)))
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
for pb.Next() { for pb.Next() {
@ -364,13 +364,13 @@ func BenchmarkSetOne_Parallel_Sjson(b *testing.B) {
func BenchmarkSetOne_Parallel_Jsoniter(b *testing.B) { func BenchmarkSetOne_Parallel_Jsoniter(b *testing.B) {
data := []byte(_TwitterJson) data := []byte(_TwitterJson)
node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{})
if !ok { if !ok {
b.Fatal(node) b.Fatal(node)
} }
b.SetBytes(int64(len(data))) b.SetBytes(int64(len(data)))
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
for pb.Next() { for pb.Next() {

View file

@ -30,9 +30,9 @@ func mem2ptr(s []byte) unsafe.Pointer {
//go:nosplit //go:nosplit
func ptr2slice(s unsafe.Pointer, l int, c int) unsafe.Pointer { func ptr2slice(s unsafe.Pointer, l int, c int) unsafe.Pointer {
slice := &rt.GoSlice{ slice := &rt.GoSlice{
Ptr: s, Ptr: s,
Len: l, Len: l,
Cap: c, Cap: c,
} }
return unsafe.Pointer(slice) return unsafe.Pointer(slice)
} }