-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscan.go
More file actions
72 lines (67 loc) · 2.1 KB
/
Copy pathscan.go
File metadata and controls
72 lines (67 loc) · 2.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package jsonx
import "unsafe"
// hasFastScan reports whether the host has a SIMD string-scan kernel
// available. Defined per-arch:
// - amd64: runtime cpuid check for AVX-512 BW (scan_amd64.go)
// - arm64: unconditionally true — NEON is mandatory in ARMv8-A
// (scan_arm64.go)
// - other arches: false (scan_other.go)
//
// The matching SIMD kernels are scanStringSIMD and skipWSSIMD, whose
// implementations live in the per-arch .s files (AVX-512BW on amd64,
// NEON on arm64). On arches without a kernel, the stubs in
// scan_other.go return 0 and are never reached since hasFastScan is
// false.
// scanString returns the offset of the first byte in p[0:n] that is '"',
// '\\', < 0x20, '<', '>', '&', or >= 0x80. The extra encoder-oriented
// breakpoints are harmless false positives for decode: decode resumes
// scalar scanning at the returned byte and only treats true JSON string
// terminators/escapes/control bytes specially.
//
// Dispatches to the SIMD kernel when hasFastScan is true and n >= 64
// (threshold amortises the broadcast/zeroupper setup cost). Falls back
// to an 8-byte SWAR scan otherwise.
func scanString(p unsafe.Pointer, n int) int {
if n <= 32 {
return scanStringTable(p, n)
}
if hasFastScan && n >= 64 {
return scanStringSIMD((*byte)(p), n)
}
return scanStringSWAR(p, n)
}
func scanStringTable(p unsafe.Pointer, n int) int {
for i := 0; i < n; i++ {
c := *(*byte)(unsafe.Pointer(uintptr(p) + uintptr(i)))
if !stringSafeSet[c] {
return i
}
}
return n
}
// scanStringSWAR is the pure-Go fallback. 8 bytes at a time via the
// stringEncodeBreakMask formula.
func scanStringSWAR(p unsafe.Pointer, n int) int {
i := 0
for i+8 <= n {
w := *(*uint64)(unsafe.Pointer(uintptr(p) + uintptr(i)))
if stringEncodeBreakMask(w) != 0 {
// precise byte position within this 8-byte window
for j := 0; j < 8; j++ {
c := *(*byte)(unsafe.Pointer(uintptr(p) + uintptr(i+j)))
if !stringSafeSet[c] {
return i + j
}
}
}
i += 8
}
for i < n {
c := *(*byte)(unsafe.Pointer(uintptr(p) + uintptr(i)))
if !stringSafeSet[c] {
return i
}
i++
}
return n
}