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 }