github.com/bytedance/sonic@v1.11.7-0.20240517092252-d2edb31b167b/ast/search.go (about) 1 /* 2 * Copyright 2021 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package ast 18 19 import ( 20 `github.com/bytedance/sonic/internal/rt` 21 `github.com/bytedance/sonic/internal/native/types` 22 ) 23 24 type Searcher struct { 25 parser Parser 26 } 27 28 func NewSearcher(str string) *Searcher { 29 return &Searcher{ 30 parser: Parser{ 31 s: str, 32 noLazy: false, 33 }, 34 } 35 } 36 37 // GetByPathCopy search in depth from top json and returns a **Copied** json node at the path location 38 func (self *Searcher) GetByPathCopy(path ...interface{}) (Node, error) { 39 return self.getByPath(true, true, path...) 40 } 41 42 // GetByPathNoCopy search in depth from top json and returns a **Referenced** json node at the path location 43 // 44 // WARN: this search directly refer partial json from top json, which has faster speed, 45 // may consumes more memory. 46 func (self *Searcher) GetByPath(path ...interface{}) (Node, error) { 47 return self.getByPath(false, true, path...) 48 } 49 50 func (self *Searcher) getByPath(copystring bool, validate bool, path ...interface{}) (Node, error) { 51 var err types.ParsingError 52 var start int 53 54 self.parser.p = 0 55 start, err = self.parser.getByPath(validate, path...) 56 if err != 0 { 57 // for compatibility with old version 58 if err == types.ERR_NOT_FOUND { 59 return Node{}, ErrNotExist 60 } 61 if err == types.ERR_UNSUPPORT_TYPE { 62 panic("path must be either int(>=0) or string") 63 } 64 return Node{}, self.parser.syntaxError(err) 65 } 66 67 t := switchRawType(self.parser.s[start]) 68 if t == _V_NONE { 69 return Node{}, self.parser.ExportError(err) 70 } 71 72 // copy string to reducing memory usage 73 var raw string 74 if copystring { 75 raw = rt.Mem2Str([]byte(self.parser.s[start:self.parser.p])) 76 } else { 77 raw = self.parser.s[start:self.parser.p] 78 } 79 return newRawNode(raw, t), nil 80 } 81 82 // GetByPath searches a path and returns relaction and types of target 83 func _GetByPath(src string, path ...interface{}) (start int, end int, typ int, err error) { 84 p := NewParserObj(src) 85 s, e := p.getByPath(false, path...) 86 if e != 0 { 87 // for compatibility with old version 88 if e == types.ERR_NOT_FOUND { 89 return -1, -1, 0, ErrNotExist 90 } 91 if e == types.ERR_UNSUPPORT_TYPE { 92 panic("path must be either int(>=0) or string") 93 } 94 return -1, -1, 0, p.syntaxError(e) 95 } 96 97 t := switchRawType(p.s[s]) 98 if t == _V_NONE { 99 return -1, -1, 0, ErrNotExist 100 } 101 if t == _V_NUMBER { 102 p.p = 1 + backward(p.s, p.p-1) 103 } 104 return s, p.p, int(t), nil 105 } 106 107 // ValidSyntax check if a json has a valid JSON syntax, 108 // while not validate UTF-8 charset 109 func _ValidSyntax(json string) bool { 110 p := NewParserObj(json) 111 _, e := p.skip() 112 if e != 0 { 113 return false 114 } 115 if skipBlank(p.s, p.p) != -int(types.ERR_EOF) { 116 return false 117 } 118 return true 119 } 120 121 // SkipFast skip a json value in fast-skip algs, 122 // while not strictly validate JSON syntax and UTF-8 charset. 123 func _SkipFast(src string, i int) (int, int, error) { 124 p := NewParserObj(src) 125 p.p = i 126 s, e := p.skipFast() 127 if e != 0 { 128 return -1, -1, p.ExportError(e) 129 } 130 t := switchRawType(p.s[s]) 131 if t == _V_NONE { 132 return -1, -1, ErrNotExist 133 } 134 if t == _V_NUMBER { 135 p.p = 1 + backward(p.s, p.p-1) 136 } 137 return s, p.p, nil 138 }