Skip to content

Commit

Permalink
feat:(ast) export API for other json lib
Browse files Browse the repository at this point in the history
  • Loading branch information
AsterDY committed Mar 12, 2024
1 parent 5d45952 commit 1feef59
Show file tree
Hide file tree
Showing 29 changed files with 7,873 additions and 7,820 deletions.
160 changes: 81 additions & 79 deletions ast/api.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build (amd64 && go1.16 && !go1.23) || (arm64 && go1.20 && !go1.23)
// +build amd64,go1.16,!go1.23 arm64,go1.20,!go1.23

/*
Expand All @@ -19,106 +20,107 @@
package ast

import (
`runtime`
`unsafe`

`github.com/bytedance/sonic/encoder`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
uq `github.com/bytedance/sonic/unquote`
"runtime"
"unsafe"

"github.com/bytedance/sonic/encoder"
"github.com/bytedance/sonic/internal/native"
"github.com/bytedance/sonic/internal/native/types"
"github.com/bytedance/sonic/internal/rt"
uq "github.com/bytedance/sonic/unquote"
)

var typeByte = rt.UnpackEface(byte(0)).Type

//go:nocheckptr
func quote(buf *[]byte, val string) {
*buf = append(*buf, '"')
if len(val) == 0 {
*buf = append(*buf, '"')
return
}

sp := rt.IndexChar(val, 0)
nb := len(val)
b := (*rt.GoSlice)(unsafe.Pointer(buf))

// input buffer
for nb > 0 {
// output buffer
dp := unsafe.Pointer(uintptr(b.Ptr) + uintptr(b.Len))
dn := b.Cap - b.Len
// call native.Quote, dn is byte count it outputs
ret := native.Quote(sp, nb, dp, &dn, 0)
// update *buf length
b.Len += dn

// no need more output
if ret >= 0 {
break
}

// double buf size
*b = growslice(typeByte, *b, b.Cap*2)
// ret is the complement of consumed input
ret = ^ret
// update input buffer
nb -= ret
sp = unsafe.Pointer(uintptr(sp) + uintptr(ret))
}

runtime.KeepAlive(buf)
runtime.KeepAlive(sp)
*buf = append(*buf, '"')
*buf = append(*buf, '"')
if len(val) == 0 {
*buf = append(*buf, '"')
return
}

sp := rt.IndexChar(val, 0)
nb := len(val)
b := (*rt.GoSlice)(unsafe.Pointer(buf))

// input buffer
for nb > 0 {
// output buffer
dp := unsafe.Pointer(uintptr(b.Ptr) + uintptr(b.Len))
dn := b.Cap - b.Len
// call native.Quote, dn is byte count it outputs
ret := native.Quote(sp, nb, dp, &dn, 0)
// update *buf length
b.Len += dn

// no need more output
if ret >= 0 {
break
}

// double buf size
*b = growslice(typeByte, *b, b.Cap*2)
// ret is the complement of consumed input
ret = ^ret
// update input buffer
nb -= ret
sp = unsafe.Pointer(uintptr(sp) + uintptr(ret))
}

runtime.KeepAlive(buf)
runtime.KeepAlive(sp)
*buf = append(*buf, '"')
}

func unquote(src string) (string, types.ParsingError) {
return uq.String(src)
// Unquote unescapes a internal JSON string (it doesn't count quotas at the begining and end)
func Unquote(src string) (string, types.ParsingError) {
return uq.String(src)
}

func (self *Parser) decodeValue() (val types.JsonState) {
sv := (*rt.GoString)(unsafe.Pointer(&self.s))
flag := types.F_USE_NUMBER
if self.dbuf != nil {
flag = 0
val.Dbuf = self.dbuf
val.Dcap = types.MaxDigitNums
}
self.p = native.Value(sv.Ptr, sv.Len, self.p, &val, uint64(flag))
return
sv := (*rt.GoString)(unsafe.Pointer(&self.s))
flag := types.F_USE_NUMBER
if self.dbuf != nil {
flag = 0
val.Dbuf = self.dbuf
val.Dcap = types.MaxDigitNums
}
self.p = native.Value(sv.Ptr, sv.Len, self.p, &val, uint64(flag))
return
}

func (self *Parser) skip() (int, types.ParsingError) {
fsm := types.NewStateMachine()
start := native.SkipOne(&self.s, &self.p, fsm, 0)
types.FreeStateMachine(fsm)

if start < 0 {
return self.p, types.ParsingError(-start)
}
return start, 0
fsm := types.NewStateMachine()
start := native.SkipOne(&self.s, &self.p, fsm, 0)
types.FreeStateMachine(fsm)

if start < 0 {
return self.p, types.ParsingError(-start)
}
return start, 0
}

func (self *Node) encodeInterface(buf *[]byte) error {
//WARN: NOT compatible with json.Encoder
return encoder.EncodeInto(buf, self.packAny(), 0)
//WARN: NOT compatible with json.Encoder
return encoder.EncodeInto(buf, self.packAny(), 0)
}

func (self *Parser) skipFast() (int, types.ParsingError) {
start := native.SkipOneFast(&self.s, &self.p)
if start < 0 {
return self.p, types.ParsingError(-start)
}
return start, 0
start := native.SkipOneFast(&self.s, &self.p)
if start < 0 {
return self.p, types.ParsingError(-start)
}
return start, 0
}

func (self *Parser) getByPath(path ...interface{}) (int, types.ParsingError) {
fsm := types.NewStateMachine()
start := native.GetByPath(&self.s, &self.p, &path, fsm)
types.FreeStateMachine(fsm)
runtime.KeepAlive(path)
if start < 0 {
return self.p, types.ParsingError(-start)
}
return start, 0
fsm := types.NewStateMachine()
start := native.GetByPath(&self.s, &self.p, &path, fsm)
types.FreeStateMachine(fsm)
runtime.KeepAlive(path)
if start < 0 {
return self.p, types.ParsingError(-start)
}
return start, 0
}
7 changes: 2 additions & 5 deletions ast/api_compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ func quote(buf *[]byte, val string) {
quoteString(buf, val)
}

func unquote(src string) (string, types.ParsingError) {
// Unquote unescapes a internal JSON string (it doesn't count quotas at the begining and end)
func Unquote(src string) (string, types.ParsingError) {
sp := rt.IndexChar(src, -1)
out, ok := unquoteBytes(rt.BytesFrom(sp, len(src)+2, len(src)+2))
if !ok {
Expand Down Expand Up @@ -97,9 +98,5 @@ func (self *Parser) getByPath(path ...interface{}) (int, types.ParsingError) {
if e != 0 {
return self.p, e
}
// t := switchRawType(self.s[start])
// if t == _V_NUMBER {
// self.p = 1 + backward(self.s, self.p-1)
// }
return start, 0
}
28 changes: 28 additions & 0 deletions ast/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -583,3 +583,31 @@ func skipArray(src string, pos int) (ret int, start int) {
pos++
}
}

// DecoderString decodes a JSON string from pos and return golang string.
// - needEsc indicates if to unescaped escaping chars
// - hasEsc tells if the returned string has escaping chars
func DecodeString(src string, pos int, needEsc bool) (v string, ret int, hasEsc bool) {
p := NewParserObj(src)
p.p = pos
switch val := p.decodeValue(); val.Vt {
case types.V_STRING:
str := p.s[val.Iv : p.p-1]
/* fast path: no escape sequence */
if val.Ep == -1 {
return str, p.p, false
} else if !needEsc {
return str, p.p, true
}
/* unquote the string */
out, err := Unquote(str)
/* check for errors */
if err != 0 {
return "", -int(err), true
} else {
return out, p.p, true
}
default:
return "", -int(_ERR_UNSUPPORT_TYPE), false
}
}
10 changes: 5 additions & 5 deletions ast/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ func (self *Parser) decodeObject(ret *linkedPairs) (Node, types.ParsingError) {

/* check for escape sequence */
if njs.Ep != -1 {
if key, err = unquote(key); err != 0 {
if key, err = Unquote(key); err != 0 {
return Node{}, err
}
}
Expand Down Expand Up @@ -274,8 +274,8 @@ func (self *Parser) decodeString(iv int64, ep int) (Node, types.ParsingError) {
return NewString(s), 0
}

/* unquote the string */
out, err := unquote(s)
/* Unquote the string */
out, err := Unquote(s)

/* check for errors */
if err != 0 {
Expand Down Expand Up @@ -355,7 +355,7 @@ func (self *Parser) searchKey(match string) types.ParsingError {

/* check for escape sequence */
if njs.Ep != -1 {
if key, err = unquote(key); err != 0 {
if key, err = Unquote(key); err != 0 {
return err
}
}
Expand Down Expand Up @@ -536,7 +536,7 @@ func (self *Node) skipNextPair() (*Pair) {

/* check for escape sequence */
if njs.Ep != -1 {
if key, err = unquote(key); err != 0 {
if key, err = Unquote(key); err != 0 {
return &Pair{key, *newSyntaxError(parser.syntaxError(err))}
}
}
Expand Down
42 changes: 42 additions & 0 deletions ast/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,45 @@ func (self *Searcher) getByPath(copystring bool, path ...interface{}) (Node, err
}
return newRawNode(raw, t), nil
}

// GetByPath searches a path and returns relaction and types of target
func GetByPath(src string, path ...interface{}) (start int, end int, typ int, err error) {
p := NewParserObj(src)
s, e := p.getByPath(path...)
if e != 0 {
// for compatibility with old version
if e == types.ERR_NOT_FOUND {
return -1, -1, 0, ErrNotExist
}
if e == types.ERR_UNSUPPORT_TYPE {
panic("path must be either int(>=0) or string")
}
return -1, -1, 0, p.syntaxError(e)
}

t := switchRawType(p.s[s])
if t == _V_NONE {
return -1, -1, 0, ErrNotExist
}
return s, p.p, int(t), nil
}

// ValidSyntax check if a json has a valid JSON syntax,
// while not validate UTF-8 charset
func ValidSyntax(json string) bool {
p := NewParserObj(json)
_, e := p.skip()
return e == 0
}

// SkipFast skip a json value in fast-skip algs,
// while not strictly validate JSON syntax and UTF-8 charset.
func SkipFast(src string, i int) (int, int, error) {
p := NewParserObj(src)
p.p = i
s, e := p.skipFast()
if e != 0 {
return -1, -1, p.ExportError(e)
}
return s, p.p, nil
}
4 changes: 2 additions & 2 deletions ast/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ func (self *traverser) decodeObject() error {

/* check for escape sequence */
if njs.Ep != -1 {
if key, err = unquote(key); err != 0 {
if key, err = Unquote(key); err != 0 {
return err
}
}
Expand Down Expand Up @@ -307,7 +307,7 @@ func (self *traverser) decodeString(iv int64, ep int) error {
}

/* unquote the string */
out, err := unquote(s)
out, err := Unquote(s)
if err != 0 {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/encoder/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ func Valid(data []byte) (ok bool, start int) {
s := rt.Mem2Str(data)
p := 0
m := types.NewStateMachine()
ret := native.ValidateOne(&s, &p, m)
ret := native.ValidateOne(&s, &p, m, types.F_VALIDATE_STRING)
types.FreeStateMachine(m)

if ret < 0 {
Expand Down
6 changes: 3 additions & 3 deletions internal/native/avx/native_amd64.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 1feef59

Please sign in to comment.