Skip to content

Commit

Permalink
Merge branch 'main' into feat/value
Browse files Browse the repository at this point in the history
  • Loading branch information
AsterDY committed Mar 4, 2024
2 parents c15a8e7 + 3739ffe commit bbf63a6
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 19 deletions.
2 changes: 1 addition & 1 deletion ast/buffer.go
Expand Up @@ -351,7 +351,7 @@ func (self *linkedPairs) Swap(i, j int) {
}

func (self *linkedPairs) Sort() {
sort.Sort(self)
sort.Stable(self)
}

// Compare two strings from the pos d.
Expand Down
49 changes: 38 additions & 11 deletions ast/node.go
Expand Up @@ -586,7 +586,7 @@ func (self *Node) Unset(key string) (bool, error) {
} else if err := p.Check(); err != nil {
return false, err
}
self.removePair(i)
self.removePairAt(i)
return true, nil
}

Expand Down Expand Up @@ -856,19 +856,30 @@ func (self *Node) IndexPair(idx int) *Pair {
return self.skipIndexPair(idx)
}

func (self *Node) indexOrGet(idx int, key string) (*Node, int) {
if err := self.should(types.V_OBJECT, "an object"); err != nil {
return unwrapError(err), idx
}

pr := self.skipIndexPair(idx)
if pr != nil && pr.Key == key {
return &pr.Value, idx
}

return self.skipKey(key)
}

// IndexOrGet firstly use idx to index a value and check if its key matches
// If not, then use the key to search value
func (self *Node) IndexOrGet(idx int, key string) *Node {
if err := self.should(types.V_OBJECT, "an object"); err != nil {
return unwrapError(err)
}
node, _ := self.indexOrGet(idx, key)
return node
}

pr := self.skipIndexPair(idx)
if pr != nil && pr.Key == key {
return &pr.Value
}
n, _ := self.skipKey(key)
return n
// IndexOrGetWithIdx attempts to retrieve a node by index and key, returning the node and its correct index.
// If the key does not match at the given index, it searches by key and returns the node with its updated index.
func (self *Node) IndexOrGetWithIdx(idx int, key string) (*Node, int) {
return self.indexOrGet(idx, key)
}

/** Generic Value Converters **/
Expand Down Expand Up @@ -965,7 +976,7 @@ func (self *Node) SortKeys(recurse bool) error {
}
if self.itype() == types.V_OBJECT {
return self.sortKeys(recurse)
} else {
} else if self.itype() == types.V_ARRAY {
var err error
err2 := self.ForEach(func(path Sequence, node *Node) bool {
it := node.itype()
Expand All @@ -981,10 +992,16 @@ func (self *Node) SortKeys(recurse bool) error {
return err
}
return err2
} else {
return nil
}
}

func (self *Node) sortKeys(recurse bool) (err error) {
// check raw node first
if err := self.checkRaw(); err != nil {
return err
}
ps, err := self.unsafeMap()
if err != nil {
return err
Expand Down Expand Up @@ -1475,6 +1492,16 @@ func (self *Node) removePair(i int) {
self.l--
}

func (self *Node) removePairAt(i int) {
p := (*linkedPairs)(self.p).At(i)
if p == nil {
return
}
*p = Pair{}
// NOTICE: should be consistent with linkedPair.Len()
self.l--
}

func (self *Node) toGenericArray() ([]interface{}, error) {
nb := self.len()
if nb == 0 {
Expand Down
39 changes: 36 additions & 3 deletions ast/node_test.go
Expand Up @@ -86,9 +86,9 @@ func BenchmarkNodeSortKeys(b *testing.B) {
if err != nil {
b.Fatal(err)
}
if err := root.LoadAll(); 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")
Expand All @@ -110,6 +110,28 @@ func BenchmarkNodeSortKeys(b *testing.B) {
})
}

func TestNodeSortKeys2(t *testing.T) {
root, err := NewSearcher(_TwitterJson).GetByPath()
if err != nil {
t.Fatal(err)
}
// if err := root.LoadAll(); err != nil {
// b.Fatal(err)
// }
t.Run("single", func(t *testing.T) {
r := root.Get("statuses")
if r.Check() != nil {
t.Fatal(r.Error())
}
require.NoError(t, root.SortKeys(false))
})
t.Run("recurse", func(t *testing.T) {
require.NoError(t, root.SortKeys(true))
})
}



//go:noinline
func stackObj() interface{} {
var a int = 1
Expand Down Expand Up @@ -250,6 +272,17 @@ func TestIndexOrGet(t *testing.T) {
}
}

func TestIndexOrGetWithIdx(t *testing.T) {
root, _ := NewParser(`{"a":1,"b":2}`).Parse()
b, idx := root.IndexOrGetWithIdx(0, "b")
if v, err := b.Int64(); err != nil || v != int64(2) {
t.Fatal(b, idx)
}
if idx != 1 {
t.Fatal(b, idx)
}
}

func TestTypeCast(t *testing.T) {
type tcase struct {
method string
Expand Down
3 changes: 1 addition & 2 deletions internal/rt/asm_amd64.s
@@ -1,5 +1,4 @@
// +build !noasm !appengine
// Code generated by asm2asm, DO NOT EDIT·
// +build !noasm,amd64 !appengine,amd64

#include "go_asm.h"
#include "funcdata.h"
Expand Down
3 changes: 1 addition & 2 deletions internal/rt/asm_arm64.s → internal/rt/asm_compat.s
@@ -1,5 +1,4 @@
// +build !noasm !appengine
// Code generated by asm2asm, DO NOT EDIT.
// +build !noasm,!amd64 !appengine,!amd64

#include "go_asm.h"
#include "funcdata.h"
Expand Down
82 changes: 82 additions & 0 deletions issue_test/issue600_test.go
@@ -0,0 +1,82 @@
/**
* Copyright 2024 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 issue_test

import (
"fmt"
"testing"

"github.com/bytedance/sonic/ast"
"github.com/stretchr/testify/require"
)


func TestIssue600(t *testing.T) {
// object
obj := ast.NewRaw("{\"x\":\"a\",\"y\":\"b\"}")
if ok, err := obj.Unset("x"); !ok || err != nil {
panic(fmt.Errorf("unset x fail, ok=%v, err=%v", ok, err))
}
if ok, err := obj.Unset("y"); !ok || err != nil {
panic(fmt.Errorf("unset y fail, ok=%v, err=%v", ok, err))
}
result, err := obj.MarshalJSON()
if err != nil {
panic(fmt.Errorf("MarshalJSON fail: err=%v", err))
}
require.Equal(t, `{}`, string(result))

obj = ast.NewRaw("{\"x\":\"a\",\"y\":\"b\"}")
if ok, err := obj.Unset("y"); !ok || err != nil {
panic(fmt.Errorf("unset x fail, ok=%v, err=%v", ok, err))
}
if ok, err := obj.Unset("x"); !ok || err != nil {
panic(fmt.Errorf("unset y fail, ok=%v, err=%v", ok, err))
}
result, err = obj.MarshalJSON()
if err != nil {
panic(fmt.Errorf("MarshalJSON fail: err=%v", err))
}
require.Equal(t, `{}`, string(result))

// array
obj = ast.NewRaw("[1,2]")
if ok, err := obj.UnsetByIndex(0); !ok || err != nil {
panic(fmt.Errorf("unset x fail, ok=%v, err=%v", ok, err))
}
if ok, err := obj.UnsetByIndex(0); !ok || err != nil {
panic(fmt.Errorf("unset y fail, ok=%v, err=%v", ok, err))
}
result, err = obj.MarshalJSON()
if err != nil {
panic(fmt.Errorf("MarshalJSON fail: err=%v", err))
}
require.Equal(t, `[]`, string(result))

obj = ast.NewRaw("[1,2]")
if ok, err := obj.UnsetByIndex(1); !ok || err != nil {
panic(fmt.Errorf("unset x fail, ok=%v, err=%v", ok, err))
}
if ok, err := obj.UnsetByIndex(0); !ok || err != nil {
panic(fmt.Errorf("unset y fail, ok=%v, err=%v", ok, err))
}
result, err = obj.MarshalJSON()
if err != nil {
panic(fmt.Errorf("MarshalJSON fail: err=%v", err))
}
require.Equal(t, `[]`, string(result))
}

0 comments on commit bbf63a6

Please sign in to comment.