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  }