summaryrefslogtreecommitdiff
path: root/vendor/github.com/bytedance/sonic/ast
diff options
context:
space:
mode:
authorLibravatar dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>2025-01-14 13:10:39 +0000
committerLibravatar GitHub <noreply@github.com>2025-01-14 13:10:39 +0000
commit4d423102c14de9e9328f1852db539d9561a3cad9 (patch)
tree6df5905f53ad7eadbfa9840939989253bfb4b199 /vendor/github.com/bytedance/sonic/ast
parent[bugfix] migration to cleanup dropped status edits (#3637) (diff)
downloadgotosocial-4d423102c14de9e9328f1852db539d9561a3cad9.tar.xz
[chore]: Bump github.com/gin-contrib/gzip from 1.0.1 to 1.1.0 (#3639)
Bumps [github.com/gin-contrib/gzip](https://github.com/gin-contrib/gzip) from 1.0.1 to 1.1.0. - [Release notes](https://github.com/gin-contrib/gzip/releases) - [Changelog](https://github.com/gin-contrib/gzip/blob/master/.goreleaser.yaml) - [Commits](https://github.com/gin-contrib/gzip/compare/v1.0.1...v1.1.0) --- updated-dependencies: - dependency-name: github.com/gin-contrib/gzip dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Diffstat (limited to 'vendor/github.com/bytedance/sonic/ast')
-rw-r--r--vendor/github.com/bytedance/sonic/ast/api.go6
-rw-r--r--vendor/github.com/bytedance/sonic/ast/api_compat.go4
-rw-r--r--vendor/github.com/bytedance/sonic/ast/b64_amd64.go31
-rw-r--r--vendor/github.com/bytedance/sonic/ast/b64_compat.go31
-rw-r--r--vendor/github.com/bytedance/sonic/ast/buffer.go89
-rw-r--r--vendor/github.com/bytedance/sonic/ast/decode.go88
-rw-r--r--vendor/github.com/bytedance/sonic/ast/encode.go55
-rw-r--r--vendor/github.com/bytedance/sonic/ast/error.go6
-rw-r--r--vendor/github.com/bytedance/sonic/ast/iterator.go21
-rw-r--r--vendor/github.com/bytedance/sonic/ast/node.go303
-rw-r--r--vendor/github.com/bytedance/sonic/ast/parser.go142
-rw-r--r--vendor/github.com/bytedance/sonic/ast/search.go31
-rw-r--r--vendor/github.com/bytedance/sonic/ast/stubs.go142
-rw-r--r--vendor/github.com/bytedance/sonic/ast/stubs_go115.go55
-rw-r--r--vendor/github.com/bytedance/sonic/ast/stubs_go120.go55
-rw-r--r--vendor/github.com/bytedance/sonic/ast/visitor.go45
16 files changed, 636 insertions, 468 deletions
diff --git a/vendor/github.com/bytedance/sonic/ast/api.go b/vendor/github.com/bytedance/sonic/ast/api.go
index 316a62a9d..7c8253aa1 100644
--- a/vendor/github.com/bytedance/sonic/ast/api.go
+++ b/vendor/github.com/bytedance/sonic/ast/api.go
@@ -1,5 +1,5 @@
-//go:build (amd64 && go1.16 && !go1.23) || (arm64 && go1.20 && !go1.23)
-// +build amd64,go1.16,!go1.23 arm64,go1.20,!go1.23
+//go:build (amd64 && go1.17 && !go1.24) || (arm64 && go1.20 && !go1.24)
+// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24
/*
* Copyright 2022 ByteDance Inc.
@@ -61,7 +61,7 @@ func quote(buf *[]byte, val string) {
}
// double buf size
- *b = growslice(typeByte, *b, b.Cap*2)
+ *b = rt.GrowSlice(typeByte, *b, b.Cap*2)
// ret is the complement of consumed input
ret = ^ret
// update input buffer
diff --git a/vendor/github.com/bytedance/sonic/ast/api_compat.go b/vendor/github.com/bytedance/sonic/ast/api_compat.go
index 82d1eacd3..a349afc0b 100644
--- a/vendor/github.com/bytedance/sonic/ast/api_compat.go
+++ b/vendor/github.com/bytedance/sonic/ast/api_compat.go
@@ -1,4 +1,4 @@
-// +build !amd64,!arm64 go1.23 !go1.16 arm64,!go1.20
+// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20
/*
* Copyright 2022 ByteDance Inc.
@@ -27,7 +27,7 @@ import (
)
func init() {
- println("WARNING:(ast) sonic only supports Go1.16~1.22, but your environment is not suitable")
+ println("WARNING:(ast) sonic only supports go1.17~1.23, but your environment is not suitable")
}
func quote(buf *[]byte, val string) {
diff --git a/vendor/github.com/bytedance/sonic/ast/b64_amd64.go b/vendor/github.com/bytedance/sonic/ast/b64_amd64.go
deleted file mode 100644
index 3e32b600b..000000000
--- a/vendor/github.com/bytedance/sonic/ast/b64_amd64.go
+++ /dev/null
@@ -1,31 +0,0 @@
-// +build amd64,go1.16
-
-/**
- * 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 (
- `github.com/cloudwego/base64x`
-)
-
-func decodeBase64(src string) ([]byte, error) {
- return base64x.StdEncoding.DecodeString(src)
-}
-
-func encodeBase64(src []byte) string {
- return base64x.StdEncoding.EncodeToString(src)
-}
diff --git a/vendor/github.com/bytedance/sonic/ast/b64_compat.go b/vendor/github.com/bytedance/sonic/ast/b64_compat.go
deleted file mode 100644
index e8f9a72fd..000000000
--- a/vendor/github.com/bytedance/sonic/ast/b64_compat.go
+++ /dev/null
@@ -1,31 +0,0 @@
-// +build !amd64 !go1.16
-
-/*
- * Copyright 2022 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 (
- `encoding/base64`
-)
-
-func decodeBase64(src string) ([]byte, error) {
- return base64.StdEncoding.DecodeString(src)
-}
-
-func encodeBase64(src []byte) string {
- return base64.StdEncoding.EncodeToString(src)
-}
diff --git a/vendor/github.com/bytedance/sonic/ast/buffer.go b/vendor/github.com/bytedance/sonic/ast/buffer.go
index bccbf4814..04701ef5b 100644
--- a/vendor/github.com/bytedance/sonic/ast/buffer.go
+++ b/vendor/github.com/bytedance/sonic/ast/buffer.go
@@ -17,8 +17,10 @@
package ast
import (
- `sort`
- `unsafe`
+ "sort"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/caching"
)
type nodeChunk [_DEFAULT_NODE_CAP]Node
@@ -90,18 +92,11 @@ func (self *linkedNodes) Pop() {
self.size--
}
-func (self *linkedPairs) Pop() {
- if self == nil || self.size == 0 {
- return
- }
- self.Set(self.size-1, Pair{})
- 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
@@ -195,11 +190,22 @@ func (self *linkedNodes) FromSlice(con []Node) {
type pairChunk [_DEFAULT_NODE_CAP]Pair
type linkedPairs struct {
+ index map[uint64]int
head pairChunk
tail []*pairChunk
size int
}
+func (self *linkedPairs) BuildIndex() {
+ if self.index == nil {
+ self.index = make(map[uint64]int, self.size)
+ }
+ for i:=0; i<self.size; i++ {
+ p := self.At(i)
+ self.index[p.hash] = i
+ }
+}
+
func (self *linkedPairs) Cap() int {
if self == nil {
return 0
@@ -233,7 +239,31 @@ func (self *linkedPairs) Push(v Pair) {
self.Set(self.size, v)
}
+func (self *linkedPairs) Pop() {
+ if self == nil || self.size == 0 {
+ return
+ }
+ self.Unset(self.size-1)
+ self.size--
+}
+
+func (self *linkedPairs) Unset(i int) {
+ if self.index != nil {
+ p := self.At(i)
+ delete(self.index, p.hash)
+ }
+ self.set(i, Pair{})
+}
+
func (self *linkedPairs) Set(i int, v Pair) {
+ if self.index != nil {
+ h := v.hash
+ self.index[h] = i
+ }
+ self.set(i, v)
+}
+
+func (self *linkedPairs) set(i int, v Pair) {
if i < _DEFAULT_NODE_CAP {
self.head[i] = v
if self.size <= i {
@@ -276,6 +306,21 @@ func (self *linkedPairs) growTailLength(l int) {
// linear search
func (self *linkedPairs) Get(key string) (*Pair, int) {
+ if self.index != nil {
+ // fast-path
+ i, ok := self.index[caching.StrHash(key)]
+ if ok {
+ n := self.At(i)
+ if n.Key == key {
+ return n, i
+ }
+ // hash conflicts
+ goto linear_search
+ } else {
+ return nil, -1
+ }
+ }
+linear_search:
for i:=0; i<self.size; i++ {
if n := self.At(i); n.Key == key {
return n, i
@@ -313,15 +358,27 @@ func (self *linkedPairs) ToMap(con map[string]Node) {
}
}
+func (self *linkedPairs) copyPairs(to []Pair, from []Pair, l int) {
+ copy(to, from)
+ if self.index != nil {
+ for i:=0; i<l; i++ {
+ // NOTICE: in case of user not pass hash, just cal it
+ h := caching.StrHash(from[i].Key)
+ from[i].hash = h
+ self.index[h] = i
+ }
+ }
+}
+
func (self *linkedPairs) FromSlice(con []Pair) {
self.size = len(con)
i := self.size-1
a, b := i/_DEFAULT_NODE_CAP-1, i%_DEFAULT_NODE_CAP
if a < 0 {
- copy(self.head[:b+1], con)
+ self.copyPairs(self.head[:b+1], con, b+1)
return
} else {
- copy(self.head[:], con)
+ self.copyPairs(self.head[:], con, len(self.head))
con = con[_DEFAULT_NODE_CAP:]
}
@@ -333,12 +390,12 @@ func (self *linkedPairs) FromSlice(con []Pair) {
for i:=0; i<a; i++ {
self.tail[i] = new(pairChunk)
- copy(self.tail[i][:], con)
+ self.copyPairs(self.tail[i][:], con, len(self.tail[i]))
con = con[_DEFAULT_NODE_CAP:]
}
self.tail[a] = new(pairChunk)
- copy(self.tail[a][:b+1], con)
+ self.copyPairs(self.tail[a][:b+1], con, b+1)
}
func (self *linkedPairs) Less(i, j int) bool {
@@ -347,6 +404,10 @@ func (self *linkedPairs) Less(i, j int) bool {
func (self *linkedPairs) Swap(i, j int) {
a, b := self.At(i), self.At(j)
+ if self.index != nil {
+ self.index[a.hash] = j
+ self.index[b.hash] = i
+ }
*a, *b = *b, *a
}
diff --git a/vendor/github.com/bytedance/sonic/ast/decode.go b/vendor/github.com/bytedance/sonic/ast/decode.go
index c521fb5f0..27aaf1408 100644
--- a/vendor/github.com/bytedance/sonic/ast/decode.go
+++ b/vendor/github.com/bytedance/sonic/ast/decode.go
@@ -17,19 +17,23 @@
package ast
import (
- `encoding/base64`
- `runtime`
- `strconv`
- `unsafe`
-
- `github.com/bytedance/sonic/internal/native/types`
- `github.com/bytedance/sonic/internal/rt`
+ "encoding/base64"
+ "runtime"
+ "strconv"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/native/types"
+ "github.com/bytedance/sonic/internal/rt"
+ "github.com/bytedance/sonic/internal/utils"
)
-const _blankCharsMask = (1 << ' ') | (1 << '\t') | (1 << '\r') | (1 << '\n')
+// Hack: this is used for both checking space and cause firendly compile errors in 32-bit arch.
+const _Sonic_Not_Support_32Bit_Arch__Checking_32Bit_Arch_Here = (1 << ' ') | (1 << '\t') | (1 << '\r') | (1 << '\n')
+
+var bytesNull = []byte("null")
const (
- bytesNull = "null"
+ strNull = "null"
bytesTrue = "true"
bytesFalse = "false"
bytesObject = "{}"
@@ -37,7 +41,7 @@ const (
)
func isSpace(c byte) bool {
- return (int(1<<c) & _blankCharsMask) != 0
+ return (int(1<<c) & _Sonic_Not_Support_32Bit_Arch__Checking_32Bit_Arch_Here) != 0
}
//go:nocheckptr
@@ -63,7 +67,7 @@ func decodeNull(src string, pos int) (ret int) {
if ret > len(src) {
return -int(types.ERR_EOF)
}
- if src[pos:ret] == bytesNull {
+ if src[pos:ret] == strNull {
return ret
} else {
return -int(types.ERR_INVALID_CHAR)
@@ -287,67 +291,7 @@ func decodeValue(src string, pos int, skipnum bool) (ret int, v types.JsonState)
//go:nocheckptr
func skipNumber(src string, pos int) (ret int) {
- sp := uintptr(rt.IndexChar(src, pos))
- se := uintptr(rt.IndexChar(src, len(src)))
- if uintptr(sp) >= se {
- return -int(types.ERR_EOF)
- }
-
- if c := *(*byte)(unsafe.Pointer(sp)); c == '-' {
- sp += 1
- }
- ss := sp
-
- var pointer bool
- var exponent bool
- var lastIsDigit bool
- var nextNeedDigit = true
-
- for ; sp < se; sp += uintptr(1) {
- c := *(*byte)(unsafe.Pointer(sp))
- if isDigit(c) {
- lastIsDigit = true
- nextNeedDigit = false
- continue
- } else if nextNeedDigit {
- return -int(types.ERR_INVALID_CHAR)
- } else if c == '.' {
- if !lastIsDigit || pointer || exponent || sp == ss {
- return -int(types.ERR_INVALID_CHAR)
- }
- pointer = true
- lastIsDigit = false
- nextNeedDigit = true
- continue
- } else if c == 'e' || c == 'E' {
- if !lastIsDigit || exponent {
- return -int(types.ERR_INVALID_CHAR)
- }
- if sp == se-1 {
- return -int(types.ERR_EOF)
- }
- exponent = true
- lastIsDigit = false
- nextNeedDigit = false
- continue
- } else if c == '-' || c == '+' {
- if prev := *(*byte)(unsafe.Pointer(sp - 1)); prev != 'e' && prev != 'E' {
- return -int(types.ERR_INVALID_CHAR)
- }
- lastIsDigit = false
- nextNeedDigit = true
- continue
- } else {
- break
- }
- }
-
- if nextNeedDigit {
- return -int(types.ERR_EOF)
- }
-
- runtime.KeepAlive(src)
- return int(uintptr(sp) - uintptr((*rt.GoString)(unsafe.Pointer(&src)).Ptr))
+ return utils.SkipNumber(src, pos)
}
//go:nocheckptr
diff --git a/vendor/github.com/bytedance/sonic/ast/encode.go b/vendor/github.com/bytedance/sonic/ast/encode.go
index 956809c2c..eae0bd258 100644
--- a/vendor/github.com/bytedance/sonic/ast/encode.go
+++ b/vendor/github.com/bytedance/sonic/ast/encode.go
@@ -17,12 +17,11 @@
package ast
import (
- `sync`
- `unicode/utf8`
-)
+ "sync"
+ "unicode/utf8"
-const (
- _MaxBuffer = 1024 // 1KB buffer size
+ "github.com/bytedance/sonic/internal/rt"
+ "github.com/bytedance/sonic/option"
)
func quoteString(e *[]byte, s string) {
@@ -30,7 +29,7 @@ func quoteString(e *[]byte, s string) {
start := 0
for i := 0; i < len(s); {
if b := s[i]; b < utf8.RuneSelf {
- if safeSet[b] {
+ if rt.SafeSet[b] {
i++
continue
}
@@ -54,8 +53,8 @@ func quoteString(e *[]byte, s string) {
// user-controlled strings are rendered into JSON
// and served to some browsers.
*e = append(*e, `u00`...)
- *e = append(*e, hex[b>>4])
- *e = append(*e, hex[b&0xF])
+ *e = append(*e, rt.Hex[b>>4])
+ *e = append(*e, rt.Hex[b&0xF])
}
i++
start = i
@@ -76,7 +75,7 @@ func quoteString(e *[]byte, s string) {
*e = append(*e, s[start:i]...)
}
*e = append(*e, `\u202`...)
- *e = append(*e, hex[c&0xF])
+ *e = append(*e, rt.Hex[c&0xF])
i += size
start = i
continue
@@ -92,16 +91,24 @@ func quoteString(e *[]byte, s string) {
var bytesPool = sync.Pool{}
func (self *Node) MarshalJSON() ([]byte, error) {
+ if self == nil {
+ return bytesNull, nil
+ }
+
buf := newBuffer()
err := self.encode(buf)
if err != nil {
freeBuffer(buf)
return nil, err
}
-
- ret := make([]byte, len(*buf))
- copy(ret, *buf)
- freeBuffer(buf)
+ var ret []byte
+ if !rt.CanSizeResue(cap(*buf)) {
+ ret = *buf
+ } else {
+ ret = make([]byte, len(*buf))
+ copy(ret, *buf)
+ freeBuffer(buf)
+ }
return ret, err
}
@@ -109,21 +116,24 @@ func newBuffer() *[]byte {
if ret := bytesPool.Get(); ret != nil {
return ret.(*[]byte)
} else {
- buf := make([]byte, 0, _MaxBuffer)
+ buf := make([]byte, 0, option.DefaultAstBufferSize)
return &buf
}
}
func freeBuffer(buf *[]byte) {
+ if !rt.CanSizeResue(cap(*buf)) {
+ return
+ }
*buf = (*buf)[:0]
bytesPool.Put(buf)
}
func (self *Node) encode(buf *[]byte) error {
- if self.IsRaw() {
+ if self.isRaw() {
return self.encodeRaw(buf)
}
- switch self.Type() {
+ switch int(self.itype()) {
case V_NONE : return ErrNotExist
case V_ERROR : return self.Check()
case V_NULL : return self.encodeNull(buf)
@@ -139,16 +149,21 @@ func (self *Node) encode(buf *[]byte) error {
}
func (self *Node) encodeRaw(buf *[]byte) error {
- raw, err := self.Raw()
- if err != nil {
- return err
+ lock := self.rlock()
+ if !self.isRaw() {
+ self.runlock()
+ return self.encode(buf)
+ }
+ raw := self.toString()
+ if lock {
+ self.runlock()
}
*buf = append(*buf, raw...)
return nil
}
func (self *Node) encodeNull(buf *[]byte) error {
- *buf = append(*buf, bytesNull...)
+ *buf = append(*buf, strNull...)
return nil
}
diff --git a/vendor/github.com/bytedance/sonic/ast/error.go b/vendor/github.com/bytedance/sonic/ast/error.go
index 00a04468e..3716e7a91 100644
--- a/vendor/github.com/bytedance/sonic/ast/error.go
+++ b/vendor/github.com/bytedance/sonic/ast/error.go
@@ -17,6 +17,10 @@ func newError(err types.ParsingError, msg string) *Node {
}
}
+func newErrorPair(err SyntaxError) *Pair {
+ return &Pair{0, "", *newSyntaxError(err)}
+}
+
// Error returns error message if the node is invalid
func (self Node) Error() string {
if self.t != V_ERROR {
@@ -79,7 +83,7 @@ func (self SyntaxError) description() string {
/* check for empty source */
if self.Src == "" {
- return fmt.Sprintf("no sources available: %#v", self)
+ return fmt.Sprintf("no sources available, the input json is empty: %#v", self)
}
/* prevent slicing before the beginning */
diff --git a/vendor/github.com/bytedance/sonic/ast/iterator.go b/vendor/github.com/bytedance/sonic/ast/iterator.go
index 64e1e5a90..076647154 100644
--- a/vendor/github.com/bytedance/sonic/ast/iterator.go
+++ b/vendor/github.com/bytedance/sonic/ast/iterator.go
@@ -17,19 +17,29 @@
package ast
import (
- `fmt`
+ "fmt"
- `github.com/bytedance/sonic/internal/native/types`
+ "github.com/bytedance/sonic/internal/caching"
+ "github.com/bytedance/sonic/internal/native/types"
)
type Pair struct {
+ hash uint64
Key string
Value Node
}
+func NewPair(key string, val Node) Pair {
+ return Pair{
+ hash: caching.StrHash(key),
+ Key: key,
+ Value: val,
+ }
+}
+
// 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 {
+ if err := self.should(types.V_ARRAY); err != nil {
return ListIterator{}, err
}
return self.values(), nil
@@ -41,7 +51,7 @@ func (self *Node) values() ListIterator {
// 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 {
+ if err := self.should(types.V_OBJECT); err != nil {
return ObjectIterator{}, err
}
return self.properties(), nil
@@ -168,6 +178,9 @@ type Scanner func(path Sequence, node *Node) bool
//
// NOTICE: A unsetted node WON'T trigger sc, but its index still counts into Path.Index
func (self *Node) ForEach(sc Scanner) error {
+ if err := self.checkRaw(); err != nil {
+ return err
+ }
switch self.itype() {
case types.V_ARRAY:
iter, err := self.Values()
diff --git a/vendor/github.com/bytedance/sonic/ast/node.go b/vendor/github.com/bytedance/sonic/ast/node.go
index ac6d22808..0fbcf7835 100644
--- a/vendor/github.com/bytedance/sonic/ast/node.go
+++ b/vendor/github.com/bytedance/sonic/ast/node.go
@@ -17,13 +17,15 @@
package ast
import (
- `encoding/json`
- `fmt`
- `strconv`
- `unsafe`
-
- `github.com/bytedance/sonic/internal/native/types`
- `github.com/bytedance/sonic/internal/rt`
+ "encoding/json"
+ "fmt"
+ "strconv"
+ "sync"
+ "sync/atomic"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/native/types"
+ "github.com/bytedance/sonic/internal/rt"
)
const (
@@ -36,7 +38,7 @@ const (
_V_ARRAY_LAZY = _V_LAZY | types.V_ARRAY
_V_OBJECT_LAZY = _V_LAZY | types.V_OBJECT
_MASK_LAZY = _V_LAZY - 1
- _MASK_RAW = _V_RAW - 1
+ _MASK_RAW = _V_RAW - 1
)
const (
@@ -56,6 +58,7 @@ type Node struct {
t types.ValueType
l uint
p unsafe.Pointer
+ m *sync.RWMutex
}
// UnmarshalJSON is just an adapter to json.Unmarshaler.
@@ -79,17 +82,39 @@ func (self *Node) UnmarshalJSON(data []byte) (err error) {
// V_STRING = 7 (json value string)
// V_NUMBER = 33 (json value number )
// V_ANY = 34 (golang interface{})
+//
+// Deprecated: not concurrent safe. Use TypeSafe instead
func (self Node) Type() int {
return int(self.t & _MASK_LAZY & _MASK_RAW)
}
-func (self Node) itype() types.ValueType {
+// Type concurrently-safe returns json type represented by the node
+// It will be one of belows:
+// V_NONE = 0 (empty node, key not exists)
+// V_ERROR = 1 (error node)
+// V_NULL = 2 (json value `null`, key exists)
+// V_TRUE = 3 (json value `true`)
+// V_FALSE = 4 (json value `false`)
+// V_ARRAY = 5 (json value array)
+// V_OBJECT = 6 (json value object)
+// V_STRING = 7 (json value string)
+// V_NUMBER = 33 (json value number )
+// V_ANY = 34 (golang interface{})
+func (self *Node) TypeSafe() int {
+ return int(self.loadt() & _MASK_LAZY & _MASK_RAW)
+}
+
+func (self *Node) itype() types.ValueType {
return self.t & _MASK_LAZY & _MASK_RAW
}
// Exists returns false only if the self is nil or empty node V_NONE
func (self *Node) Exists() bool {
- return self.Valid() && self.t != _V_NONE
+ if self == nil {
+ return false
+ }
+ t := self.loadt()
+ return t != V_ERROR && t != _V_NONE
}
// Valid reports if self is NOT V_ERROR or nil
@@ -97,7 +122,7 @@ func (self *Node) Valid() bool {
if self == nil {
return false
}
- return self.t != V_ERROR
+ return self.loadt() != V_ERROR
}
// Check checks if the node itself is valid, and return:
@@ -106,24 +131,31 @@ func (self *Node) Valid() bool {
func (self *Node) Check() error {
if self == nil {
return ErrNotExist
- } else if self.t != V_ERROR {
+ } else if self.loadt() != V_ERROR {
return nil
} else {
return self
}
}
-// IsRaw returns true if node's underlying value is raw json
+// isRaw returns true if node's underlying value is raw json
+//
+// Deprecated: not concurent safe
func (self Node) IsRaw() bool {
- return self.t&_V_RAW != 0
+ return self.t & _V_RAW != 0
+}
+
+// IsRaw returns true if node's underlying value is raw json
+func (self *Node) isRaw() bool {
+ return self.loadt() & _V_RAW != 0
}
func (self *Node) isLazy() bool {
- return self != nil && 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
+ return self != nil && self.loadt() == _V_ANY
}
/** Simple Value Methods **/
@@ -133,18 +165,26 @@ func (self *Node) Raw() (string, error) {
if self == nil {
return "", ErrNotExist
}
- if !self.IsRaw() {
+ lock := self.rlock()
+ if !self.isRaw() {
+ if lock {
+ self.runlock()
+ }
buf, err := self.MarshalJSON()
return rt.Mem2Str(buf), err
}
- return self.toString(), nil
+ ret := self.toString()
+ if lock {
+ self.runlock()
+ }
+ return ret, nil
}
func (self *Node) checkRaw() error {
if err := self.Check(); err != nil {
return err
}
- if self.IsRaw() {
+ if self.isRaw() {
self.parseRaw(false)
}
return self.Check()
@@ -504,7 +544,7 @@ func (self *Node) Len() (int, error) {
}
}
-func (self Node) len() int {
+func (self *Node) len() int {
return int(self.l)
}
@@ -527,7 +567,7 @@ func (self *Node) Cap() (int, error) {
//
// 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) {
- if err := self.Check(); err != nil {
+ if err := self.checkRaw(); err != nil {
return false, err
}
if err := node.Check(); err != nil {
@@ -535,7 +575,7 @@ func (self *Node) Set(key string, node Node) (bool, error) {
}
if self.t == _V_NONE || self.t == types.V_NULL {
- *self = NewObject([]Pair{{key, node}})
+ *self = NewObject([]Pair{NewPair(key, node)})
return false, nil
} else if self.itype() != types.V_OBJECT {
return false, ErrUnsupportType
@@ -549,7 +589,7 @@ func (self *Node) Set(key string, node Node) (bool, error) {
*self = newObject(new(linkedPairs))
}
s := (*linkedPairs)(self.p)
- s.Push(Pair{key, node})
+ s.Push(NewPair(key, node))
self.l++
return false, nil
@@ -568,7 +608,7 @@ func (self *Node) SetAny(key string, val interface{}) (bool, error) {
// Unset REMOVE (soft) the node of given key under object parent, and reports if the key has existed.
func (self *Node) Unset(key string) (bool, error) {
- if err := self.should(types.V_OBJECT, "an object"); err != nil {
+ if err := self.should(types.V_OBJECT); err != nil {
return false, err
}
// NOTICE: must get acurate length before deduct
@@ -589,7 +629,7 @@ func (self *Node) Unset(key string) (bool, error) {
//
// The index must be within self's children.
func (self *Node) SetByIndex(index int, node Node) (bool, error) {
- if err := self.Check(); err != nil {
+ if err := self.checkRaw(); err != nil {
return false, err
}
if err := node.Check(); err != nil {
@@ -669,7 +709,7 @@ func (self *Node) UnsetByIndex(index int) (bool, error) {
//
// 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 {
- if err := self.Check(); err != nil {
+ if err := self.checkRaw(); err != nil {
return err
}
@@ -677,7 +717,7 @@ func (self *Node) Add(node Node) error {
*self = NewArray([]Node{node})
return nil
}
- if err := self.should(types.V_ARRAY, "an array"); err != nil {
+ if err := self.should(types.V_ARRAY); err != nil {
return err
}
@@ -740,7 +780,7 @@ func (self *Node) Pop() error {
//
// WARN: this will change address of elements, which is a dangerous action.
func (self *Node) Move(dst, src int) error {
- if err := self.should(types.V_ARRAY, "an array"); err != nil {
+ if err := self.should(types.V_ARRAY); err != nil {
return err
}
@@ -812,7 +852,7 @@ func (self *Node) GetByPath(path ...interface{}) *Node {
// Get loads given key of an object node on demands
func (self *Node) Get(key string) *Node {
- if err := self.should(types.V_OBJECT, "an object"); err != nil {
+ if err := self.should(types.V_OBJECT); err != nil {
return unwrapError(err)
}
n, _ := self.skipKey(key)
@@ -845,14 +885,14 @@ func (self *Node) Index(idx int) *Node {
// IndexPair indexies pair at given idx,
// node type MUST be either V_OBJECT
func (self *Node) IndexPair(idx int) *Pair {
- if err := self.should(types.V_OBJECT, "an object"); err != nil {
+ if err := self.should(types.V_OBJECT); err != nil {
return nil
}
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 {
+ if err := self.should(types.V_OBJECT); err != nil {
return unwrapError(err), idx
}
@@ -889,10 +929,10 @@ func (self *Node) Map() (map[string]interface{}, error) {
return nil, ErrUnsupportType
}
}
- if err := self.should(types.V_OBJECT, "an object"); err != nil {
+ if err := self.should(types.V_OBJECT); err != nil {
return nil, err
}
- if err := self.loadAllKey(); err != nil {
+ if err := self.loadAllKey(false); err != nil {
return nil, err
}
return self.toGenericObject()
@@ -908,10 +948,10 @@ func (self *Node) MapUseNumber() (map[string]interface{}, error) {
return nil, ErrUnsupportType
}
}
- if err := self.should(types.V_OBJECT, "an object"); err != nil {
+ if err := self.should(types.V_OBJECT); err != nil {
return nil, err
}
- if err := self.loadAllKey(); err != nil {
+ if err := self.loadAllKey(false); err != nil {
return nil, err
}
return self.toGenericObjectUseNumber()
@@ -928,7 +968,7 @@ func (self *Node) MapUseNode() (map[string]Node, error) {
return nil, ErrUnsupportType
}
}
- if err := self.should(types.V_OBJECT, "an object"); err != nil {
+ if err := self.should(types.V_OBJECT); err != nil {
return nil, err
}
if err := self.skipAllKey(); err != nil {
@@ -1034,10 +1074,10 @@ func (self *Node) Array() ([]interface{}, error) {
return nil, ErrUnsupportType
}
}
- if err := self.should(types.V_ARRAY, "an array"); err != nil {
+ if err := self.should(types.V_ARRAY); err != nil {
return nil, err
}
- if err := self.loadAllIndex(); err != nil {
+ if err := self.loadAllIndex(false); err != nil {
return nil, err
}
return self.toGenericArray()
@@ -1053,10 +1093,10 @@ func (self *Node) ArrayUseNumber() ([]interface{}, error) {
return nil, ErrUnsupportType
}
}
- if err := self.should(types.V_ARRAY, "an array"); err != nil {
+ if err := self.should(types.V_ARRAY); err != nil {
return nil, err
}
- if err := self.loadAllIndex(); err != nil {
+ if err := self.loadAllIndex(false); err != nil {
return nil, err
}
return self.toGenericArrayUseNumber()
@@ -1073,7 +1113,7 @@ func (self *Node) ArrayUseNode() ([]Node, error) {
return nil, ErrUnsupportType
}
}
- if err := self.should(types.V_ARRAY, "an array"); err != nil {
+ if err := self.should(types.V_ARRAY); err != nil {
return nil, err
}
if err := self.skipAllIndex(); err != nil {
@@ -1129,12 +1169,12 @@ func (self *Node) Interface() (interface{}, error) {
}
return v, nil
case _V_ARRAY_LAZY :
- if err := self.loadAllIndex(); err != nil {
+ if err := self.loadAllIndex(false); err != nil {
return nil, err
}
return self.toGenericArray()
case _V_OBJECT_LAZY :
- if err := self.loadAllKey(); err != nil {
+ if err := self.loadAllKey(false); err != nil {
return nil, err
}
return self.toGenericObject()
@@ -1168,12 +1208,12 @@ func (self *Node) InterfaceUseNumber() (interface{}, error) {
case types.V_STRING : return self.toString(), nil
case _V_NUMBER : return self.toNumber(), nil
case _V_ARRAY_LAZY :
- if err := self.loadAllIndex(); err != nil {
+ if err := self.loadAllIndex(false); err != nil {
return nil, err
}
return self.toGenericArrayUseNumber()
case _V_OBJECT_LAZY :
- if err := self.loadAllKey(); err != nil {
+ if err := self.loadAllKey(false); err != nil {
return nil, err
}
return self.toGenericObjectUseNumber()
@@ -1205,70 +1245,30 @@ func (self *Node) InterfaceUseNode() (interface{}, error) {
}
}
-// LoadAll loads all the node's children and children's children as parsed.
-// After calling it, the node can be safely used on concurrency
+// LoadAll loads the node's children
+// and ensure all its children can be READ concurrently (include its children's children)
func (self *Node) LoadAll() error {
- if self.IsRaw() {
- self.parseRaw(true)
- return self.Check()
- }
-
- switch self.itype() {
- case types.V_ARRAY:
- e := self.len()
- if err := self.loadAllIndex(); err != nil {
- return err
- }
- for i := 0; i < e; i++ {
- n := self.nodeAt(i)
- if n.IsRaw() {
- n.parseRaw(true)
- }
- if err := n.Check(); err != nil {
- return err
- }
- }
- return nil
- case types.V_OBJECT:
- e := self.len()
- if err := self.loadAllKey(); err != nil {
- return err
- }
- for i := 0; i < e; i++ {
- n := self.pairAt(i)
- if n.Value.IsRaw() {
- n.Value.parseRaw(true)
- }
- if err := n.Value.Check(); err != nil {
- return err
- }
- }
- return nil
- default:
- return self.Check()
- }
+ return self.Load()
}
// Load loads the node's children as parsed.
-// After calling it, only the node itself can be used on concurrency (not include its children)
+// and ensure all its children can be READ concurrently (include its children's children)
func (self *Node) Load() error {
- if err := self.checkRaw(); err != nil {
- return err
- }
-
switch self.t {
- case _V_ARRAY_LAZY:
- return self.skipAllIndex()
- case _V_OBJECT_LAZY:
- return self.skipAllKey()
- default:
- return self.Check()
+ case _V_ARRAY_LAZY: self.loadAllIndex(true)
+ case _V_OBJECT_LAZY: self.loadAllKey(true)
+ case V_ERROR: return self
+ case V_NONE: return nil
}
+ if self.m == nil {
+ self.m = new(sync.RWMutex)
+ }
+ return self.checkRaw()
}
/**---------------------------------- Internal Helper Methods ----------------------------------**/
-func (self *Node) should(t types.ValueType, s string) error {
+func (self *Node) should(t types.ValueType) error {
if err := self.checkRaw(); err != nil {
return err
}
@@ -1439,13 +1439,17 @@ func (self *Node) skipIndexPair(index int) *Pair {
return nil
}
-func (self *Node) loadAllIndex() error {
+func (self *Node) loadAllIndex(loadOnce bool) error {
if !self.isLazy() {
return nil
}
var err types.ParsingError
parser, stack := self.getParserAndArrayStack()
- parser.noLazy = true
+ if !loadOnce {
+ parser.noLazy = true
+ } else {
+ parser.loadOnce = true
+ }
*self, err = parser.decodeArray(&stack.v)
if err != 0 {
return parser.ExportError(err)
@@ -1453,14 +1457,19 @@ func (self *Node) loadAllIndex() error {
return nil
}
-func (self *Node) loadAllKey() error {
+func (self *Node) loadAllKey(loadOnce bool) error {
if !self.isLazy() {
return nil
}
var err types.ParsingError
parser, stack := self.getParserAndObjectStack()
- parser.noLazy = true
- *self, err = parser.decodeObject(&stack.v)
+ if !loadOnce {
+ parser.noLazy = true
+ *self, err = parser.decodeObject(&stack.v)
+ } else {
+ parser.loadOnce = true
+ *self, err = parser.decodeObject(&stack.v)
+ }
if err != 0 {
return parser.ExportError(err)
}
@@ -1629,7 +1638,23 @@ func NewRaw(json string) Node {
if it == _V_NONE {
return Node{}
}
- return newRawNode(parser.s[start:parser.p], it)
+ return newRawNode(parser.s[start:parser.p], it, false)
+}
+
+// NewRawConcurrentRead creates a node of raw json, which can be READ
+// (GetByPath/Get/Index/GetOrIndex/Int64/Bool/Float64/String/Number/Interface/Array/Map/Raw/MarshalJSON) concurrently.
+// If the input json is invalid, NewRaw returns a error Node.
+func NewRawConcurrentRead(json string) Node {
+ parser := NewParserObj(json)
+ start, err := parser.skip()
+ if err != 0 {
+ return *newError(err, err.Message())
+ }
+ it := switchRawType(parser.s[start])
+ if it == _V_NONE {
+ return Node{}
+ }
+ return newRawNode(parser.s[start:parser.p], it, true)
}
// NewAny creates a node of type V_ANY if any's type isn't Node or *Node,
@@ -1653,7 +1678,7 @@ func NewBytes(src []byte) Node {
if len(src) == 0 {
panic("empty src bytes")
}
- out := encodeBase64(src)
+ out := rt.EncodeBase64(src)
return NewString(out)
}
@@ -1689,15 +1714,15 @@ func NewNumber(v string) Node {
}
}
-func (node Node) toNumber() json.Number {
+func (node *Node) toNumber() json.Number {
return json.Number(rt.StrFrom(node.p, int64(node.l)))
}
-func (self Node) toString() string {
+func (self *Node) toString() string {
return rt.StrFrom(self.p, int64(self.l))
}
-func (node Node) toFloat64() (float64, error) {
+func (node *Node) toFloat64() (float64, error) {
ret, err := node.toNumber().Float64()
if err != nil {
return 0, err
@@ -1705,7 +1730,7 @@ func (node Node) toFloat64() (float64, error) {
return ret, nil
}
-func (node Node) toInt64() (int64, error) {
+func (node *Node) toInt64() (int64, error) {
ret,err := node.toNumber().Int64()
if err != nil {
return 0, err
@@ -1741,6 +1766,8 @@ func NewArray(v []Node) Node {
return newArray(s)
}
+const _Threshold_Index = 16
+
func newArray(v *linkedNodes) Node {
return Node{
t: types.V_ARRAY,
@@ -1764,6 +1791,9 @@ func NewObject(v []Pair) Node {
}
func newObject(v *linkedPairs) Node {
+ if v.size > _Threshold_Index {
+ v.BuildIndex()
+ }
return Node{
t: types.V_OBJECT,
l: uint(v.Len()),
@@ -1772,53 +1802,42 @@ func newObject(v *linkedPairs) Node {
}
func (self *Node) setObject(v *linkedPairs) {
+ if v.size > _Threshold_Index {
+ v.BuildIndex()
+ }
self.t = types.V_OBJECT
self.l = uint(v.Len())
self.p = unsafe.Pointer(v)
}
-func newRawNode(str string, typ types.ValueType) Node {
- return Node{
- t: _V_RAW | typ,
- p: rt.StrPtr(str),
- l: uint(len(str)),
- }
-}
-
func (self *Node) parseRaw(full bool) {
+ lock := self.lock()
+ defer self.unlock()
+ if !self.isRaw() {
+ return
+ }
raw := self.toString()
parser := NewParserObj(raw)
+ var e types.ParsingError
if full {
parser.noLazy = true
- parser.skipValue = false
+ *self, e = parser.Parse()
+ } else if lock {
+ var n Node
+ parser.noLazy = true
+ parser.loadOnce = true
+ n, e = parser.Parse()
+ self.assign(n)
+ } else {
+ *self, e = parser.Parse()
}
- var e types.ParsingError
- *self, e = parser.Parse()
if e != 0 {
*self = *newSyntaxError(parser.syntaxError(e))
}
}
-var typeJumpTable = [256]types.ValueType{
- '"' : types.V_STRING,
- '-' : _V_NUMBER,
- '0' : _V_NUMBER,
- '1' : _V_NUMBER,
- '2' : _V_NUMBER,
- '3' : _V_NUMBER,
- '4' : _V_NUMBER,
- '5' : _V_NUMBER,
- '6' : _V_NUMBER,
- '7' : _V_NUMBER,
- '8' : _V_NUMBER,
- '9' : _V_NUMBER,
- '[' : types.V_ARRAY,
- 'f' : types.V_FALSE,
- 'n' : types.V_NULL,
- 't' : types.V_TRUE,
- '{' : types.V_OBJECT,
-}
-
-func switchRawType(c byte) types.ValueType {
- return typeJumpTable[c]
+func (self *Node) assign(n Node) {
+ self.l = n.l
+ self.p = n.p
+ atomic.StoreInt64(&self.t, n.t)
}
diff --git a/vendor/github.com/bytedance/sonic/ast/parser.go b/vendor/github.com/bytedance/sonic/ast/parser.go
index a1f582623..30bd1f451 100644
--- a/vendor/github.com/bytedance/sonic/ast/parser.go
+++ b/vendor/github.com/bytedance/sonic/ast/parser.go
@@ -17,14 +17,16 @@
package ast
import (
- `fmt`
+ "fmt"
+ "sync"
+ "sync/atomic"
- `github.com/bytedance/sonic/internal/native/types`
- `github.com/bytedance/sonic/internal/rt`
+ "github.com/bytedance/sonic/internal/native/types"
+ "github.com/bytedance/sonic/internal/rt"
)
const (
- _DEFAULT_NODE_CAP int = 8
+ _DEFAULT_NODE_CAP int = 16
_APPEND_GROW_SHIFT = 1
)
@@ -45,6 +47,7 @@ type Parser struct {
p int
s string
noLazy bool
+ loadOnce bool
skipValue bool
dbuf *byte
}
@@ -115,6 +118,10 @@ func (self *Parser) lspace(sp int) int {
return sp
}
+func (self *Parser) backward() {
+ for ; self.p >= 0 && isSpace(self.s[self.p]); self.p-=1 {}
+}
+
func (self *Parser) decodeArray(ret *linkedNodes) (Node, types.ParsingError) {
sp := self.p
ns := len(self.s)
@@ -148,7 +155,7 @@ func (self *Parser) decodeArray(ret *linkedNodes) (Node, types.ParsingError) {
if t == _V_NONE {
return Node{}, types.ERR_INVALID_CHAR
}
- val = newRawNode(self.s[start:self.p], t)
+ val = newRawNode(self.s[start:self.p], t, false)
}else{
/* decode the value */
if val, err = self.Parse(); err != 0 {
@@ -234,7 +241,7 @@ func (self *Parser) decodeObject(ret *linkedPairs) (Node, types.ParsingError) {
if t == _V_NONE {
return Node{}, types.ERR_INVALID_CHAR
}
- val = newRawNode(self.s[start:self.p], t)
+ val = newRawNode(self.s[start:self.p], t, false)
} else {
/* decode the value */
if val, err = self.Parse(); err != 0 {
@@ -244,7 +251,7 @@ func (self *Parser) decodeObject(ret *linkedPairs) (Node, types.ParsingError) {
/* add the value to result */
// FIXME: ret's address may change here, thus previous referred node in ret may be invalid !!
- ret.Push(Pair{Key: key, Value: val})
+ ret.Push(NewPair(key, val))
self.p = self.lspace(self.p)
/* check for EOF */
@@ -291,6 +298,10 @@ func (self *Parser) Pos() int {
return self.p
}
+
+// Parse returns a ast.Node representing the parser's JSON.
+// NOTICE: the specific parsing lazy dependens parser's option
+// It only parse first layer and first child for Object or Array be default
func (self *Parser) Parse() (Node, types.ParsingError) {
switch val := self.decodeValue(); val.Vt {
case types.V_EOF : return Node{}, types.ERR_EOF
@@ -299,22 +310,48 @@ func (self *Parser) Parse() (Node, types.ParsingError) {
case types.V_FALSE : return falseNode, 0
case types.V_STRING : return self.decodeString(val.Iv, val.Ep)
case types.V_ARRAY:
+ s := self.p - 1;
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == ']' {
self.p = p + 1
return Node{t: types.V_ARRAY}, 0
}
if self.noLazy {
+ if self.loadOnce {
+ self.noLazy = false
+ }
return self.decodeArray(new(linkedNodes))
}
+ // NOTICE: loadOnce always keep raw json for object or array
+ if self.loadOnce {
+ self.p = s
+ s, e := self.skipFast()
+ if e != 0 {
+ return Node{}, e
+ }
+ return newRawNode(self.s[s:self.p], types.V_ARRAY, true), 0
+ }
return newLazyArray(self), 0
case types.V_OBJECT:
+ s := self.p - 1;
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == '}' {
self.p = p + 1
return Node{t: types.V_OBJECT}, 0
}
+ // NOTICE: loadOnce always keep raw json for object or array
if self.noLazy {
+ if self.loadOnce {
+ self.noLazy = false
+ }
return self.decodeObject(new(linkedPairs))
}
+ if self.loadOnce {
+ self.p = s
+ s, e := self.skipFast()
+ if e != 0 {
+ return Node{}, e
+ }
+ return newRawNode(self.s[s:self.p], types.V_OBJECT, true), 0
+ }
return newLazyObject(self), 0
case types.V_DOUBLE : return NewNumber(self.s[val.Ep:self.p]), 0
case types.V_INTEGER : return NewNumber(self.s[val.Ep:self.p]), 0
@@ -471,7 +508,7 @@ func (self *Node) skipNextNode() *Node {
if t == _V_NONE {
return newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))
}
- val = newRawNode(parser.s[start:parser.p], t)
+ val = newRawNode(parser.s[start:parser.p], t, false)
}
/* add the value to result */
@@ -510,7 +547,7 @@ func (self *Node) skipNextPair() (*Pair) {
/* check for EOF */
if parser.p = parser.lspace(sp); parser.p >= ns {
- return &Pair{"", *newSyntaxError(parser.syntaxError(types.ERR_EOF))}
+ return newErrorPair(parser.syntaxError(types.ERR_EOF))
}
/* check for empty object */
@@ -527,7 +564,7 @@ func (self *Node) skipNextPair() (*Pair) {
/* decode the key */
if njs = parser.decodeValue(); njs.Vt != types.V_STRING {
- return &Pair{"", *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))}
+ return newErrorPair(parser.syntaxError(types.ERR_INVALID_CHAR))
}
/* extract the key */
@@ -537,34 +574,34 @@ func (self *Node) skipNextPair() (*Pair) {
/* check for escape sequence */
if njs.Ep != -1 {
if key, err = unquote(key); err != 0 {
- return &Pair{key, *newSyntaxError(parser.syntaxError(err))}
+ return newErrorPair(parser.syntaxError(err))
}
}
/* expect a ':' delimiter */
if err = parser.delim(); err != 0 {
- return &Pair{key, *newSyntaxError(parser.syntaxError(err))}
+ return newErrorPair(parser.syntaxError(err))
}
/* skip the value */
if start, err := parser.skipFast(); err != 0 {
- return &Pair{key, *newSyntaxError(parser.syntaxError(err))}
+ return newErrorPair(parser.syntaxError(err))
} else {
t := switchRawType(parser.s[start])
if t == _V_NONE {
- return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))}
+ return newErrorPair(parser.syntaxError(types.ERR_INVALID_CHAR))
}
- val = newRawNode(parser.s[start:parser.p], t)
+ val = newRawNode(parser.s[start:parser.p], t, false)
}
/* add the value to result */
- ret.Push(Pair{Key: key, Value: val})
+ ret.Push(NewPair(key, val))
self.l++
parser.p = parser.lspace(parser.p)
/* check for EOF */
if parser.p >= ns {
- return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_EOF))}
+ return newErrorPair(parser.syntaxError(types.ERR_EOF))
}
/* check for the next character */
@@ -577,7 +614,7 @@ func (self *Node) skipNextPair() (*Pair) {
self.setObject(ret)
return ret.At(ret.Len()-1)
default:
- return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))}
+ return newErrorPair(parser.syntaxError(types.ERR_INVALID_CHAR))
}
}
@@ -658,3 +695,72 @@ func backward(src string, i int) int {
for ; i>=0 && isSpace(src[i]); i-- {}
return i
}
+
+
+func newRawNode(str string, typ types.ValueType, lock bool) Node {
+ ret := Node{
+ t: typ | _V_RAW,
+ p: rt.StrPtr(str),
+ l: uint(len(str)),
+ }
+ if lock {
+ ret.m = new(sync.RWMutex)
+ }
+ return ret
+}
+
+var typeJumpTable = [256]types.ValueType{
+ '"' : types.V_STRING,
+ '-' : _V_NUMBER,
+ '0' : _V_NUMBER,
+ '1' : _V_NUMBER,
+ '2' : _V_NUMBER,
+ '3' : _V_NUMBER,
+ '4' : _V_NUMBER,
+ '5' : _V_NUMBER,
+ '6' : _V_NUMBER,
+ '7' : _V_NUMBER,
+ '8' : _V_NUMBER,
+ '9' : _V_NUMBER,
+ '[' : types.V_ARRAY,
+ 'f' : types.V_FALSE,
+ 'n' : types.V_NULL,
+ 't' : types.V_TRUE,
+ '{' : types.V_OBJECT,
+}
+
+func switchRawType(c byte) types.ValueType {
+ return typeJumpTable[c]
+}
+
+func (self *Node) loadt() types.ValueType {
+ return (types.ValueType)(atomic.LoadInt64(&self.t))
+}
+
+func (self *Node) lock() bool {
+ if m := self.m; m != nil {
+ m.Lock()
+ return true
+ }
+ return false
+}
+
+func (self *Node) unlock() {
+ if m := self.m; m != nil {
+ m.Unlock()
+ }
+}
+
+func (self *Node) rlock() bool {
+ if m := self.m; m != nil {
+ m.RLock()
+ return true
+ }
+ return false
+}
+
+func (self *Node) runlock() {
+ if m := self.m; m != nil {
+ m.RUnlock()
+ }
+}
diff --git a/vendor/github.com/bytedance/sonic/ast/search.go b/vendor/github.com/bytedance/sonic/ast/search.go
index a8d1e76f6..9a5fb9420 100644
--- a/vendor/github.com/bytedance/sonic/ast/search.go
+++ b/vendor/github.com/bytedance/sonic/ast/search.go
@@ -21,8 +21,23 @@ import (
`github.com/bytedance/sonic/internal/native/types`
)
+// SearchOptions controls Searcher's behavior
+type SearchOptions struct {
+ // ValidateJSON indicates the searcher to validate the entire JSON
+ ValidateJSON bool
+
+ // CopyReturn indicates the searcher to copy the result JSON instead of refer from the input
+ // This can help to reduce memory usage if you cache the results
+ CopyReturn bool
+
+ // ConcurrentRead indicates the searcher to return a concurrently-READ-safe node,
+ // including: GetByPath/Get/Index/GetOrIndex/Int64/Bool/Float64/String/Number/Interface/Array/Map/Raw/MarshalJSON
+ ConcurrentRead bool
+}
+
type Searcher struct {
parser Parser
+ SearchOptions
}
func NewSearcher(str string) *Searcher {
@@ -31,12 +46,16 @@ func NewSearcher(str string) *Searcher {
s: str,
noLazy: false,
},
+ SearchOptions: SearchOptions{
+ ValidateJSON: true,
+ },
}
}
// GetByPathCopy search in depth from top json and returns a **Copied** json node at the path location
func (self *Searcher) GetByPathCopy(path ...interface{}) (Node, error) {
- return self.getByPath(true, true, path...)
+ self.CopyReturn = true
+ return self.getByPath(path...)
}
// GetByPathNoCopy search in depth from top json and returns a **Referenced** json node at the path location
@@ -44,15 +63,15 @@ func (self *Searcher) GetByPathCopy(path ...interface{}) (Node, error) {
// WARN: this search directly refer partial json from top json, which has faster speed,
// may consumes more memory.
func (self *Searcher) GetByPath(path ...interface{}) (Node, error) {
- return self.getByPath(false, true, path...)
+ return self.getByPath(path...)
}
-func (self *Searcher) getByPath(copystring bool, validate bool, path ...interface{}) (Node, error) {
+func (self *Searcher) getByPath(path ...interface{}) (Node, error) {
var err types.ParsingError
var start int
self.parser.p = 0
- start, err = self.parser.getByPath(validate, path...)
+ start, err = self.parser.getByPath(self.ValidateJSON, path...)
if err != 0 {
// for compatibility with old version
if err == types.ERR_NOT_FOUND {
@@ -71,12 +90,12 @@ func (self *Searcher) getByPath(copystring bool, validate bool, path ...interfac
// copy string to reducing memory usage
var raw string
- if copystring {
+ if self.CopyReturn {
raw = rt.Mem2Str([]byte(self.parser.s[start:self.parser.p]))
} else {
raw = self.parser.s[start:self.parser.p]
}
- return newRawNode(raw, t), nil
+ return newRawNode(raw, t, self.ConcurrentRead), nil
}
// GetByPath searches a path and returns relaction and types of target
diff --git a/vendor/github.com/bytedance/sonic/ast/stubs.go b/vendor/github.com/bytedance/sonic/ast/stubs.go
new file mode 100644
index 000000000..53bf3b8aa
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/ast/stubs.go
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2021 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 (
+ "unicode/utf8"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/rt"
+)
+
+//go:noescape
+//go:linkname memmove runtime.memmove
+//goland:noinspection GoUnusedParameter
+func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
+
+//go:linkname unsafe_NewArray reflect.unsafe_NewArray
+//goland:noinspection GoUnusedParameter
+func unsafe_NewArray(typ *rt.GoType, n int) unsafe.Pointer
+
+//go:nosplit
+func mem2ptr(s []byte) unsafe.Pointer {
+ return (*rt.GoSlice)(unsafe.Pointer(&s)).Ptr
+}
+
+var safeSet = [utf8.RuneSelf]bool{
+ ' ': true,
+ '!': true,
+ '"': false,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': true,
+ '\'': true,
+ '(': true,
+ ')': true,
+ '*': true,
+ '+': true,
+ ',': true,
+ '-': true,
+ '.': true,
+ '/': true,
+ '0': true,
+ '1': true,
+ '2': true,
+ '3': true,
+ '4': true,
+ '5': true,
+ '6': true,
+ '7': true,
+ '8': true,
+ '9': true,
+ ':': true,
+ ';': true,
+ '<': true,
+ '=': true,
+ '>': true,
+ '?': true,
+ '@': true,
+ 'A': true,
+ 'B': true,
+ 'C': true,
+ 'D': true,
+ 'E': true,
+ 'F': true,
+ 'G': true,
+ 'H': true,
+ 'I': true,
+ 'J': true,
+ 'K': true,
+ 'L': true,
+ 'M': true,
+ 'N': true,
+ 'O': true,
+ 'P': true,
+ 'Q': true,
+ 'R': true,
+ 'S': true,
+ 'T': true,
+ 'U': true,
+ 'V': true,
+ 'W': true,
+ 'X': true,
+ 'Y': true,
+ 'Z': true,
+ '[': true,
+ '\\': false,
+ ']': true,
+ '^': true,
+ '_': true,
+ '`': true,
+ 'a': true,
+ 'b': true,
+ 'c': true,
+ 'd': true,
+ 'e': true,
+ 'f': true,
+ 'g': true,
+ 'h': true,
+ 'i': true,
+ 'j': true,
+ 'k': true,
+ 'l': true,
+ 'm': true,
+ 'n': true,
+ 'o': true,
+ 'p': true,
+ 'q': true,
+ 'r': true,
+ 's': true,
+ 't': true,
+ 'u': true,
+ 'v': true,
+ 'w': true,
+ 'x': true,
+ 'y': true,
+ 'z': true,
+ '{': true,
+ '|': true,
+ '}': true,
+ '~': true,
+ '\u007f': true,
+}
+
+var hex = "0123456789abcdef"
+
+//go:linkname unquoteBytes encoding/json.unquoteBytes
+func unquoteBytes(s []byte) (t []byte, ok bool)
diff --git a/vendor/github.com/bytedance/sonic/ast/stubs_go115.go b/vendor/github.com/bytedance/sonic/ast/stubs_go115.go
deleted file mode 100644
index 37b9451f0..000000000
--- a/vendor/github.com/bytedance/sonic/ast/stubs_go115.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// +build !go1.20
-
-/*
- * Copyright 2021 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 (
- `unsafe`
- `unicode/utf8`
-
- `github.com/bytedance/sonic/internal/rt`
-)
-
-//go:noescape
-//go:linkname memmove runtime.memmove
-//goland:noinspection GoUnusedParameter
-func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
-
-//go:linkname unsafe_NewArray reflect.unsafe_NewArray
-//goland:noinspection GoUnusedParameter
-func unsafe_NewArray(typ *rt.GoType, n int) unsafe.Pointer
-
-//go:linkname growslice runtime.growslice
-//goland:noinspection GoUnusedParameter
-func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
-
-//go:nosplit
-func mem2ptr(s []byte) unsafe.Pointer {
- return (*rt.GoSlice)(unsafe.Pointer(&s)).Ptr
-}
-
-var (
- //go:linkname safeSet encoding/json.safeSet
- safeSet [utf8.RuneSelf]bool
-
- //go:linkname hex encoding/json.hex
- hex string
-)
-
-//go:linkname unquoteBytes encoding/json.unquoteBytes
-func unquoteBytes(s []byte) (t []byte, ok bool) \ No newline at end of file
diff --git a/vendor/github.com/bytedance/sonic/ast/stubs_go120.go b/vendor/github.com/bytedance/sonic/ast/stubs_go120.go
deleted file mode 100644
index 6f830529d..000000000
--- a/vendor/github.com/bytedance/sonic/ast/stubs_go120.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// +build go1.20
-
-/*
- * Copyright 2021 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 (
- `unsafe`
- `unicode/utf8`
-
- `github.com/bytedance/sonic/internal/rt`
-)
-
-//go:noescape
-//go:linkname memmove runtime.memmove
-//goland:noinspection GoUnusedParameter
-func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
-
-//go:linkname unsafe_NewArray reflect.unsafe_NewArray
-//goland:noinspection GoUnusedParameter
-func unsafe_NewArray(typ *rt.GoType, n int) unsafe.Pointer
-
-//go:linkname growslice reflect.growslice
-//goland:noinspection GoUnusedParameter
-func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
-
-//go:nosplit
-func mem2ptr(s []byte) unsafe.Pointer {
- return (*rt.GoSlice)(unsafe.Pointer(&s)).Ptr
-}
-
-var (
- //go:linkname safeSet encoding/json.safeSet
- safeSet [utf8.RuneSelf]bool
-
- //go:linkname hex encoding/json.hex
- hex string
-)
-
-//go:linkname unquoteBytes encoding/json.unquoteBytes
-func unquoteBytes(s []byte) (t []byte, ok bool)
diff --git a/vendor/github.com/bytedance/sonic/ast/visitor.go b/vendor/github.com/bytedance/sonic/ast/visitor.go
index d409509f5..dc0478513 100644
--- a/vendor/github.com/bytedance/sonic/ast/visitor.go
+++ b/vendor/github.com/bytedance/sonic/ast/visitor.go
@@ -18,6 +18,7 @@ package ast
import (
`encoding/json`
+ `errors`
`github.com/bytedance/sonic/internal/native/types`
)
@@ -174,6 +175,19 @@ func (self *traverser) decodeArray() error {
sp := self.parser.p
ns := len(self.parser.s)
+ /* allocate array space and parse every element */
+ if err := self.visitor.OnArrayBegin(_DEFAULT_NODE_CAP); err != nil {
+ if err == VisitOPSkip {
+ // NOTICE: for user needs to skip entiry object
+ self.parser.p -= 1
+ if _, e := self.parser.skipFast(); e != 0 {
+ return e
+ }
+ return self.visitor.OnArrayEnd()
+ }
+ return err
+ }
+
/* check for EOF */
self.parser.p = self.parser.lspace(sp)
if self.parser.p >= ns {
@@ -183,16 +197,9 @@ func (self *traverser) decodeArray() error {
/* check for empty array */
if self.parser.s[self.parser.p] == ']' {
self.parser.p++
- if err := self.visitor.OnArrayBegin(0); err != nil {
- return err
- }
return self.visitor.OnArrayEnd()
}
- /* allocate array space and parse every element */
- if err := self.visitor.OnArrayBegin(_DEFAULT_NODE_CAP); err != nil {
- return err
- }
for {
/* decode the value */
if err := self.decodeValue(); err != nil {
@@ -223,6 +230,19 @@ func (self *traverser) decodeObject() error {
sp := self.parser.p
ns := len(self.parser.s)
+ /* allocate object space and decode each pair */
+ if err := self.visitor.OnObjectBegin(_DEFAULT_NODE_CAP); err != nil {
+ if err == VisitOPSkip {
+ // NOTICE: for user needs to skip entiry object
+ self.parser.p -= 1
+ if _, e := self.parser.skipFast(); e != 0 {
+ return e
+ }
+ return self.visitor.OnObjectEnd()
+ }
+ return err
+ }
+
/* check for EOF */
self.parser.p = self.parser.lspace(sp)
if self.parser.p >= ns {
@@ -232,16 +252,9 @@ func (self *traverser) decodeObject() error {
/* check for empty object */
if self.parser.s[self.parser.p] == '}' {
self.parser.p++
- if err := self.visitor.OnObjectBegin(0); err != nil {
- return err
- }
return self.visitor.OnObjectEnd()
}
- /* allocate object space and decode each pair */
- if err := self.visitor.OnObjectBegin(_DEFAULT_NODE_CAP); err != nil {
- return err
- }
for {
var njs types.JsonState
var err types.ParsingError
@@ -313,3 +326,7 @@ func (self *traverser) decodeString(iv int64, ep int) error {
}
return self.visitor.OnString(out)
}
+
+// If visitor return this error on `OnObjectBegin()` or `OnArrayBegin()`,
+// the transverer will skip entiry object or array
+var VisitOPSkip = errors.New("")