diff --git a/ast/buffer.go b/ast/buffer.go index 4eac215b4..acd02e5e7 100644 --- a/ast/buffer.go +++ b/ast/buffer.go @@ -73,29 +73,81 @@ func (self *linkedNodes) At(i int) (*Node) { return nil } -func (self *linkedNodes) Add(v Node) { - if self.size < _DEFAULT_NODE_CAP { - self.head[self.size] = v - self.size++ +func (self *linkedNodes) MoveOne(source int, target int) { + if source == target { return } + if source < 0 || source >= self.size || target < 0 || target >= self.size { + return + } + // reserve source + n := *self.At(source) + if source < target { + // move every element (source,target] one step back + for i:=source; itarget; i-- { + *self.At(i) = *self.At(i-1) + } + } + // set target + *self.At(target) = n +} + +func (self *linkedNodes) Pop() { + if self == nil || self.size == 0 { + return + } + self.Set(self.size-1, Node{}) + self.size-- +} + +func (self *linkedNodes) Push(v Node) { + self.Set(self.size, v) +} + +func (self *linkedNodes) Set(i int, v Node) { + if i < _DEFAULT_NODE_CAP { + self.head[i] = v + if self.size <= i { + self.size = i+1 + } + return + } + a, b := i/_DEFAULT_NODE_CAP-1, i%_DEFAULT_NODE_CAP + if a < 0 { + self.head[b] = v + } else { + self.growTailLength(a+1) + var n = &self.tail[a] + if *n == nil { + *n = new(nodeChunk) + } + (*n)[b] = v + } + if self.size <= i { + self.size = i+1 + } +} - a, b, c := self.size/_DEFAULT_NODE_CAP-1 , self.size%_DEFAULT_NODE_CAP, cap(self.tail) - if a - c >= 0 { +func (self *linkedNodes) growTailLength(l int) { + if l <= len(self.tail) { + return + } + c := cap(self.tail) + for c < l { c += 1 + c>>_APPEND_GROW_SHIFT - tmp := make([]*nodeChunk, a + 1, c) - copy(tmp, self.tail) - self.tail = tmp - } else if a >= len(self.tail) { - self.tail = self.tail[:a+1] } - - var n = &self.tail[a] - if *n == nil { - *n = new(nodeChunk) + if c == cap(self.tail) { + self.tail = self.tail[:l] + return } - (*n)[b] = v - self.size++ + tmp := make([]*nodeChunk, l, c) + copy(tmp, self.tail) + self.tail = tmp } func (self *linkedNodes) ToSlice(con []Node) { @@ -184,29 +236,81 @@ func (self *linkedPairs) At(i int) *Pair { return nil } -func (self *linkedPairs) Add(v Pair) { - if self.size < _DEFAULT_NODE_CAP { - self.head[self.size] = v - self.size++ +func (self *linkedPairs) Push(v Pair) { + self.Set(self.size, v) +} + +func (self *linkedPairs) MoveOne(source int, target int) { + if source == target { + return + } + if source < 0 || source >= self.size || target < 0 || target >= self.size { return } + // reserve source + n := *self.At(source) + if source < target { + // move every element (source,target] one step back + for i:=source; itarget; i-- { + *self.At(i) = *self.At(i-1) + } + } + // set target + *self.At(target) = n +} - a, b, c := self.size/_DEFAULT_NODE_CAP-1 , self.size%_DEFAULT_NODE_CAP, cap(self.tail) - if a - c >= 0 { - c += 1 + c>>_APPEND_GROW_SHIFT - tmp := make([]*pairChunk, a + 1, c) - copy(tmp, self.tail) - self.tail = tmp - } else if a >= len(self.tail) { - self.tail = self.tail[:a+1] +func (self *linkedPairs) Pop() { + if self == nil || self.size == 0 { + return } + self.Set(self.size-1, Pair{}) + self.size-- +} - var n = &self.tail[a] - if *n == nil { - *n = new(pairChunk) +func (self *linkedPairs) Set(i int, v Pair) { + if i < _DEFAULT_NODE_CAP { + self.head[i] = v + if self.size <= i { + self.size = i+1 + } + return + } + a, b := i/_DEFAULT_NODE_CAP-1, i%_DEFAULT_NODE_CAP + if a < 0 { + self.head[b] = v + } else { + self.growTailLength(a+1) + var n = &self.tail[a] + if *n == nil { + *n = new(pairChunk) + } + (*n)[b] = v + } + if self.size <= i { + self.size = i+1 + } +} + +func (self *linkedPairs) growTailLength(l int) { + if l <= len(self.tail) { + return + } + c := cap(self.tail) + for c < l { + c += 1 + c>>_APPEND_GROW_SHIFT + } + if c == cap(self.tail) { + self.tail = self.tail[:l] + return } - (*n)[b] = v - self.size++ + tmp := make([]*pairChunk, l, c) + copy(tmp, self.tail) + self.tail = tmp } // linear search diff --git a/ast/buffer_test.go b/ast/buffer_test.go new file mode 100644 index 000000000..56da9099a --- /dev/null +++ b/ast/buffer_test.go @@ -0,0 +1,341 @@ +/** + * Copyright 2023 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ast + +import ( + "strconv" + "testing" + + "github.com/stretchr/testify/require" +) + +func makeNodes(l int) []Node { + r := make([]Node, l) + for i := 0; i < l; i++ { + r[i] = NewBool(true) + } + return r +} + +func makePairs(l int) []Pair { + r := make([]Pair, l) + for i := 0; i < l; i++ { + r[i] = Pair{strconv.Itoa(i), NewBool(true)} + } + return r +} + +func Test_linkedPairs_Push(t *testing.T) { + type args struct { + in []Pair + v Pair + exp []Pair + } + tests := []struct { + name string + args args + }{ + { + name: "add empty", + args: args{ + in: []Pair{}, + v: Pair{"a", NewBool(true)}, + exp: []Pair{Pair{"a", NewBool(true)}}, + }, + }, + { + name: "add one", + args: args{ + in: []Pair{{"a", NewBool(false)}}, + v: Pair{"b", NewBool(true)}, + exp: []Pair{{"a", NewBool(false)}, {"b", NewBool(true)}}, + }, + }, + { + name: "add _DEFAULT_NODE_CAP", + args: args{ + in: makePairs(_DEFAULT_NODE_CAP), + v: Pair{strconv.Itoa(_DEFAULT_NODE_CAP), NewBool(true)}, + exp: makePairs(_DEFAULT_NODE_CAP+1), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + self := &linkedPairs{} + self.FromSlice(tt.args.in) + self.Push(tt.args.v) + act := make([]Pair, self.Len()) + self.ToSlice(act) + require.Equal(t, tt.args.exp, act) + }) + } +} + +func Test_linkedPairs_Pop(t *testing.T) { + type args struct { + in []Pair + exp []Pair + } + tests := []struct { + name string + args args + }{ + { + name: "remove empty", + args: args{ + in: []Pair{}, + exp: []Pair{}, + }, + }, + { + name: "remove one", + args: args{ + in: []Pair{{"a", NewBool(false)}}, + exp: []Pair{}, + }, + }, + { + name: "add _DEFAULT_NODE_CAP", + args: args{ + in: makePairs(_DEFAULT_NODE_CAP), + exp: makePairs(_DEFAULT_NODE_CAP-1), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + self := &linkedPairs{} + self.FromSlice(tt.args.in) + self.Pop() + act := make([]Pair, self.Len()) + self.ToSlice(act) + require.Equal(t, tt.args.exp, act) + }) + } +} + +func Test_linkedNodes_Push(t *testing.T) { + type args struct { + in []Node + v Node + exp []Node + } + tests := []struct { + name string + args args + }{ + { + name: "add empty", + args: args{ + in: []Node{}, + v: NewBool(true), + exp: []Node{NewBool(true)}, + }, + }, + { + name: "add one", + args: args{ + in: []Node{NewBool(false)}, + v: NewBool(true), + exp: []Node{NewBool(false), NewBool(true)}, + }, + }, + { + name: "add _DEFAULT_NODE_CAP", + args: args{ + in: makeNodes(_DEFAULT_NODE_CAP), + v: NewBool(true), + exp: makeNodes(_DEFAULT_NODE_CAP+1), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + self := &linkedNodes{} + self.FromSlice(tt.args.in) + self.Push(tt.args.v) + act := make([]Node, self.Len()) + self.ToSlice(act) + require.Equal(t, tt.args.exp, act) + }) + } +} + +func Test_linkedNodes_Pop(t *testing.T) { + type args struct { + in []Node + exp []Node + } + tests := []struct { + name string + args args + }{ + { + name: "remove empty", + args: args{ + in: []Node{}, + exp: []Node{}, + }, + }, + { + name: "remove one", + args: args{ + in: []Node{NewBool(false)}, + exp: []Node{}, + }, + }, + { + name: "add _DEFAULT_NODE_CAP", + args: args{ + in: makeNodes(_DEFAULT_NODE_CAP), + exp: makeNodes(_DEFAULT_NODE_CAP-1), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + self := &linkedNodes{} + self.FromSlice(tt.args.in) + self.Pop() + act := make([]Node, self.Len()) + self.ToSlice(act) + require.Equal(t, tt.args.exp, act) + }) + } +} + +func Test_linkedNodes_MoveOne(t *testing.T) { + type args struct { + in []Node + source int + target int + exp []Node + } + tests := []struct { + name string + args args + }{ + { + name: "over index", + args: args{ + in: []Node{NewBool(true)}, + source: 1, + target: 0, + exp: []Node{NewBool(true)}, + }, + }, + { + name: "equal index", + args: args{ + in: []Node{NewBool(true)}, + source: 0, + target: 0, + exp: []Node{NewBool(true)}, + }, + }, + { + name: "forward index", + args: args{ + in: []Node{NewString("a"), NewString("b"), NewString("c")}, + source: 0, + target: 2, + exp: []Node{NewString("b"), NewString("c"), NewString("a")}, + }, + }, + { + name: "backward index", + args: args{ + in: []Node{NewString("a"), NewString("b"), NewString("c")}, + source: 2, + target: 1, + exp: []Node{NewString("a"), NewString("c"), NewString("b")}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + self := &linkedNodes{} + self.FromSlice(tt.args.in) + self.MoveOne(tt.args.source, tt.args.target) + act := make([]Node, self.Len()) + self.ToSlice(act) + require.Equal(t, tt.args.exp, act) + }) + } +} + +func Test_linkedPairs_MoveOne(t *testing.T) { + type args struct { + in []Pair + source int + target int + exp []Pair + } + tests := []struct { + name string + args args + }{ + { + name: "over index", + args: args{ + in: []Pair{{"a", NewBool(true)}}, + source: 1, + target: 0, + exp: []Pair{{"a", NewBool(true)}}, + }, + }, + { + name: "equal index", + args: args{ + in: []Pair{{"a", NewBool(true)}}, + source: 0, + target: 0, + exp: []Pair{{"a", NewBool(true)}}, + }, + }, + { + name: "forward index", + args: args{ + in: []Pair{{"a", NewString("a")}, {"b", NewString("b")}, {"c", NewString("c")}}, + source: 0, + target: 2, + exp: []Pair{{"b", NewString("b")}, {"c", NewString("c")}, {"a", NewString("a")}}, + }, + }, + { + name: "backward index", + args: args{ + in: []Pair{{"a", NewString("a")}, {"b", NewString("b")}, {"c", NewString("c")}}, + source: 2, + target: 1, + exp: []Pair{{"a", NewString("a")}, {"c", NewString("c")}, {"b", NewString("b")}}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + self := &linkedPairs{} + self.FromSlice(tt.args.in) + self.MoveOne(tt.args.source, tt.args.target) + act := make([]Pair, self.Len()) + self.ToSlice(act) + require.Equal(t, tt.args.exp, act) + }) + } +} + diff --git a/ast/node.go b/ast/node.go index 9a2efff92..8f0860843 100644 --- a/ast/node.go +++ b/ast/node.go @@ -549,7 +549,7 @@ func (self *Node) Set(key string, node Node) (bool, error) { *self = newObject(new(linkedPairs)) } s := (*linkedPairs)(self.p) - s.Add(Pair{key, node}) + s.Push(Pair{key, node}) self.l++ return false, nil @@ -678,11 +678,40 @@ func (self *Node) Add(node Node) error { return err } - s.Add(node) + s.Push(node) self.l++ return nil } +// Pop remove the last child of the V_Array node. +func (self *Node) Pop() error { + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return err + } + + s, err := self.unsafeArray() + if err != nil { + return err + } + + s.Pop() + self.l-- + return nil +} + +func (self *Node) Move(src, dst int) error { + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return err + } + + s, err := self.unsafeArray() + if err != nil { + return err + } + + s.MoveOne(src, dst) + return nil +} // SetAny wraps val with V_ANY node, and Add() the node. func (self *Node) AddAny(val interface{}) error { diff --git a/ast/node_test.go b/ast/node_test.go index b330a6798..ba35fd3a0 100644 --- a/ast/node_test.go +++ b/ast/node_test.go @@ -17,758 +17,755 @@ package ast import ( - `bytes` - `encoding/json` - `errors` - `fmt` - `reflect` - `runtime` - `runtime/debug` - `strconv` - `testing` - - `github.com/bytedance/sonic/internal/native/types` - `github.com/bytedance/sonic/internal/rt` - `github.com/stretchr/testify/assert` - `github.com/stretchr/testify/require` + "bytes" + "encoding/json" + "errors" + "fmt" + "reflect" + "runtime" + "runtime/debug" + "strconv" + "testing" + + "github.com/bytedance/sonic/internal/native/types" + "github.com/bytedance/sonic/internal/rt" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) - func TestNodeSortKeys(t *testing.T) { - var src = `{"b":1,"a":2,"c":3}` - root, err := NewSearcher(src).GetByPath() - if err != nil { - t.Fatal(err) - } - obj, err := root.MapUseNumber() - if err != nil { - t.Fatal(err) - } - exp, err := json.Marshal(obj) - if err != nil { - t.Fatal(err) - } - if err := root.SortKeys(true); err != nil { - t.Fatal(err) - } - act, err := root.MarshalJSON() - if err != nil { - t.Fatal(err) - } - assert.Equal(t, len(exp), len(act)) - assert.Equal(t, string(exp), string(act)) - - src = `[[1], {"b":1,"a":2,"c":3}, [], {}, [{"b":1,"a":2,"c":3,"d":[],"e":{}}]]` - root, err = NewSearcher(src).GetByPath() - if err != nil { - t.Fatal(err) - } - vv, err := root.Interface() - if err != nil { - t.Fatal(err) - } - exp, err = json.Marshal(vv) - if err != nil { - t.Fatal(err) - } - if err := root.SortKeys(true); err != nil { - t.Fatal(err) - } - act, err = root.MarshalJSON() - if err != nil { - t.Fatal(err) - } - assert.Equal(t, string(exp), string(act)) + var src = `{"b":1,"a":2,"c":3}` + root, err := NewSearcher(src).GetByPath() + if err != nil { + t.Fatal(err) + } + obj, err := root.MapUseNumber() + if err != nil { + t.Fatal(err) + } + exp, err := json.Marshal(obj) + if err != nil { + t.Fatal(err) + } + if err := root.SortKeys(true); err != nil { + t.Fatal(err) + } + act, err := root.MarshalJSON() + if err != nil { + t.Fatal(err) + } + assert.Equal(t, len(exp), len(act)) + assert.Equal(t, string(exp), string(act)) + + src = `[[1], {"b":1,"a":2,"c":3}, [], {}, [{"b":1,"a":2,"c":3,"d":[],"e":{}}]]` + root, err = NewSearcher(src).GetByPath() + if err != nil { + t.Fatal(err) + } + vv, err := root.Interface() + if err != nil { + t.Fatal(err) + } + exp, err = json.Marshal(vv) + if err != nil { + t.Fatal(err) + } + if err := root.SortKeys(true); err != nil { + t.Fatal(err) + } + act, err = root.MarshalJSON() + if err != nil { + t.Fatal(err) + } + assert.Equal(t, string(exp), string(act)) } func BenchmarkNodeSortKeys(b *testing.B) { - root, err := NewSearcher(_TwitterJson).GetByPath() - if err != nil { - b.Fatal(err) - } - if err := root.LoadAll(); err != nil { - b.Fatal(err) - } - - b.Run("single", func(b *testing.B) { - r := root.Get("statuses") - if r.Check() != nil { - b.Fatal(r.Error()) - } - b.SetBytes(int64(len(_TwitterJson))) - b.ResetTimer() - for i:=0; i= 0; i-- { - root.GetByPath("statuses", 3).Set("id_str"+strconv.Itoa(i), app) - } - val, _ = root.GetByPath("statuses", 3, "id_str0").Int64() - if val != 111 { - t.Fatalf("exp: %+v, got: %+v", 111, val) - } - - nroot, derr := NewParser(`{"a":[0.1,true,0,"name",{"b":"c"}]}`).Parse() - if derr != 0 { - t.Fatalf("decode failed: %v", derr.Error()) - } - root.GetByPath("statuses", 3).Set("id_str2", nroot) - val2, _ := root.GetByPath("statuses", 3, "id_str2", "a", 4, "b").String() - if val2 != "c" { - t.Fatalf("exp:%+v, got:%+v", "c", val2) - } + arr := NewRaw(`[]`) + ex, ee := arr.Set("a", NewNumber("-1")) + if ex || ee == nil { + t.Fatal() + } + 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() + if derr != 0 { + t.Fatalf("decode failed: %v", derr.Error()) + } + app, _ := NewParser("111").Parse() + root.GetByPath("statuses", 3).Set("id_str", app) + val, _ := root.GetByPath("statuses", 3, "id_str").Int64() + if val != 111 { + t.Fatalf("exp: %+v, got: %+v", 111, val) + } + for i, _ := root.GetByPath("statuses", 3).Cap(); i >= 0; i-- { + root.GetByPath("statuses", 3).Set("id_str"+strconv.Itoa(i), app) + } + val, _ = root.GetByPath("statuses", 3, "id_str0").Int64() + if val != 111 { + t.Fatalf("exp: %+v, got: %+v", 111, val) + } + + nroot, derr := NewParser(`{"a":[0.1,true,0,"name",{"b":"c"}]}`).Parse() + if derr != 0 { + t.Fatalf("decode failed: %v", derr.Error()) + } + root.GetByPath("statuses", 3).Set("id_str2", nroot) + val2, _ := root.GetByPath("statuses", 3, "id_str2", "a", 4, "b").String() + if val2 != "c" { + t.Fatalf("exp:%+v, got:%+v", "c", val2) + } } 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)) - } + 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) { - root, derr := NewParser(_TwitterJson).Parse() - if derr != 0 { - t.Fatalf("decode failed: %v", derr.Error()) - } - app, _ := NewParser("111").Parse() - st := root.GetByPath("statuses") - st.SetByIndex(0, app) - st = root.GetByPath("statuses") - val := st.Index(0) - x, _ := val.Int64() - if x != 111 { - t.Fatalf("exp: %+v, got: %+v", 111, val) - } - - nroot, derr := NewParser(`{"a":[0.1,true,0,"name",{"b":"c"}]}`).Parse() - if derr != 0 { - t.Fatalf("decode failed: %v", derr.Error()) - } - root.GetByPath("statuses").SetByIndex(0, nroot) - val2, _ := root.GetByPath("statuses", 0, "a", 4, "b").String() - if val2 != "c" { - t.Fatalf("exp:%+v, got:%+v", "c", val2) - } + root, derr := NewParser(_TwitterJson).Parse() + if derr != 0 { + t.Fatalf("decode failed: %v", derr.Error()) + } + app, _ := NewParser("111").Parse() + st := root.GetByPath("statuses") + st.SetByIndex(0, app) + st = root.GetByPath("statuses") + val := st.Index(0) + x, _ := val.Int64() + if x != 111 { + t.Fatalf("exp: %+v, got: %+v", 111, val) + } + + nroot, derr := NewParser(`{"a":[0.1,true,0,"name",{"b":"c"}]}`).Parse() + if derr != 0 { + t.Fatalf("decode failed: %v", derr.Error()) + } + root.GetByPath("statuses").SetByIndex(0, nroot) + val2, _ := root.GetByPath("statuses", 0, "a", 4, "b").String() + if val2 != "c" { + t.Fatalf("exp:%+v, got:%+v", "c", val2) + } } func TestNodeAdd(t *testing.T) { - root, derr := NewParser(_TwitterJson).Parse() - if derr != 0 { - t.Fatalf("decode failed: %v", derr.Error()) - } - app, _ := NewParser("111").Parse() - - for i, _ := root.GetByPath("statuses").Cap(); i >= 0; i-- { - root.GetByPath("statuses").Add(app) - } - val, _ := root.GetByPath("statuses", 4).Int64() - if val != 111 { - t.Fatalf("exp: %+v, got: %+v", 111, val) - } - val, _ = root.GetByPath("statuses", root.GetByPath("statuses").len()-1).Int64() - if val != 111 { - t.Fatalf("exp: %+v, got: %+v", 111, val) - } - - nroot, derr := NewParser(`{"a":[0.1,true,0,"name",{"b":"c"}]}`).Parse() - if derr != 0 { - t.Fatalf("decode failed: %v", derr.Error()) - } - root.GetByPath("statuses").Add(nroot) - val2, _ := root.GetByPath("statuses", root.GetByPath("statuses").len()-1, "a", 4, "b").String() - if val2 != "c" { - t.Fatalf("exp:%+v, got:%+v", "c", val2) - } + root, derr := NewParser(_TwitterJson).Parse() + if derr != 0 { + t.Fatalf("decode failed: %v", derr.Error()) + } + app, _ := NewParser("111").Parse() + + for i, _ := root.GetByPath("statuses").Cap(); i >= 0; i-- { + root.GetByPath("statuses").Add(app) + } + val, _ := root.GetByPath("statuses", 4).Int64() + if val != 111 { + t.Fatalf("exp: %+v, got: %+v", 111, val) + } + val, _ = root.GetByPath("statuses", root.GetByPath("statuses").len()-1).Int64() + if val != 111 { + t.Fatalf("exp: %+v, got: %+v", 111, val) + } + + nroot, derr := NewParser(`{"a":[0.1,true,0,"name",{"b":"c"}]}`).Parse() + if derr != 0 { + t.Fatalf("decode failed: %v", derr.Error()) + } + root.GetByPath("statuses").Add(nroot) + val2, _ := root.GetByPath("statuses", root.GetByPath("statuses").len()-1, "a", 4, "b").String() + if val2 != "c" { + t.Fatalf("exp:%+v, got:%+v", "c", val2) + } } func BenchmarkLoadNode(b *testing.B) { - b.Run("Interface()", func(b *testing.B) { - b.SetBytes(int64(len(_TwitterJson))) - b.ResetTimer() - for i:=0; i