[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>
This commit is contained in:
dependabot[bot] 2025-01-14 13:10:39 +00:00 committed by GitHub
commit 4d423102c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
519 changed files with 156968 additions and 132058 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -17,19 +17,23 @@
package ast
import (
`encoding/base64`
`runtime`
`strconv`
`unsafe`
"encoding/base64"
"runtime"
"strconv"
"unsafe"
`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"
"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

View file

@ -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
}

View file

@ -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 */

View file

@ -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()

View file

@ -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)
}

View file

@ -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()
}
}

View file

@ -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

142
vendor/github.com/bytedance/sonic/ast/stubs.go generated vendored Normal file
View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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("")