skip.go raw

   1  
   2  package utils
   3  
   4  import (
   5      `runtime`
   6      `unsafe`
   7  
   8      `github.com/bytedance/sonic/internal/native/types`
   9      `github.com/bytedance/sonic/internal/rt`
  10  )
  11  
  12  func isDigit(c byte) bool {
  13      return c >= '0' && c <= '9'
  14  }
  15  
  16  //go:nocheckptr
  17  func SkipNumber(src string, pos int) (ret int) {
  18      sp := uintptr(rt.IndexChar(src, pos))
  19      se := uintptr(rt.IndexChar(src, len(src)))
  20      if uintptr(sp) >= se {
  21          return -int(types.ERR_EOF)
  22      }
  23  
  24      if c := *(*byte)(unsafe.Pointer(sp)); c == '-' {
  25          sp += 1
  26      }
  27      ss := sp
  28  
  29      var pointer bool
  30      var exponent bool
  31      var lastIsDigit bool
  32      var nextNeedDigit = true
  33  
  34      for ; sp < se; sp += uintptr(1) {
  35          c := *(*byte)(unsafe.Pointer(sp))
  36          if isDigit(c) {
  37              lastIsDigit = true
  38              nextNeedDigit = false
  39              continue
  40          } else if nextNeedDigit {
  41              return -int(types.ERR_INVALID_CHAR)
  42          } else if c == '.' {
  43              if !lastIsDigit || pointer || exponent || sp == ss {
  44                  return -int(types.ERR_INVALID_CHAR)
  45              }
  46              pointer = true
  47              lastIsDigit = false
  48              nextNeedDigit = true
  49              continue
  50          } else if c == 'e' || c == 'E' {
  51              if !lastIsDigit || exponent {
  52                  return -int(types.ERR_INVALID_CHAR)
  53              }
  54              if sp == se-1 {
  55                  return -int(types.ERR_EOF)
  56              }
  57              exponent = true
  58              lastIsDigit = false
  59              nextNeedDigit = false
  60              continue
  61          } else if c == '-' || c == '+' {
  62              if prev := *(*byte)(unsafe.Pointer(sp - 1)); prev != 'e' && prev != 'E' {
  63                  return -int(types.ERR_INVALID_CHAR)
  64              }
  65              lastIsDigit = false
  66              nextNeedDigit = true
  67              continue
  68          } else {
  69              break
  70          }
  71      }
  72  
  73      if nextNeedDigit {
  74          return -int(types.ERR_EOF)
  75      }
  76  
  77      runtime.KeepAlive(src)
  78      return int(uintptr(sp) - uintptr((*rt.GoString)(unsafe.Pointer(&src)).Ptr))
  79  }