1package jsoncolor
2
3import "unsafe"
4
5// asciiValid returns true if b contains only ASCII characters.
6//
7// From https://github.com/segmentio/encoding/blob/v0.1.14/ascii/valid.go#L28
8//
9//go:nosplit
10func asciiValid(b []byte) bool {
11 s, n := unsafe.Pointer(&b), uintptr(len(b))
12
13 i := uintptr(0)
14 p := *(*unsafe.Pointer)(s)
15
16 for n >= 8 {
17 if ((*(*uint64)(unsafe.Pointer(uintptr(p) + i))) & 0x8080808080808080) != 0 {
18 return false
19 }
20 i += 8
21 n -= 8
22 }
23
24 if n >= 4 {
25 if ((*(*uint32)(unsafe.Pointer(uintptr(p) + i))) & 0x80808080) != 0 {
26 return false
27 }
28 i += 4
29 n -= 4
30 }
31
32 var x uint32
33 switch n {
34 case 3:
35 x = uint32(*(*uint8)(unsafe.Pointer(uintptr(p) + i))) | uint32(*(*uint16)(unsafe.Pointer(uintptr(p) + i + 1)))<<8
36 case 2:
37 x = uint32(*(*uint16)(unsafe.Pointer(uintptr(p) + i)))
38 case 1:
39 x = uint32(*(*uint8)(unsafe.Pointer(uintptr(p) + i)))
40 default:
41 return true
42 }
43 return (x & 0x80808080) == 0
44}
45
46// asciiValidPrint returns true if b contains only printable ASCII characters.
47//
48// From https://github.com/segmentio/encoding/blob/v0.1.14/ascii/valid.go#L83
49//
50//go:nosplit
51func asciiValidPrint(b []byte) bool {
52 s, n := unsafe.Pointer(&b), uintptr(len(b))
53
54 if n == 0 {
55 return true
56 }
57
58 i := uintptr(0)
59 p := *(*unsafe.Pointer)(s)
60
61 for (n - i) >= 8 {
62 x := *(*uint64)(unsafe.Pointer(uintptr(p) + i))
63 if hasLess64(x, 0x20) || hasMore64(x, 0x7e) {
64 return false
65 }
66 i += 8
67 }
68
69 if (n - i) >= 4 {
70 x := *(*uint32)(unsafe.Pointer(uintptr(p) + i))
71 if hasLess32(x, 0x20) || hasMore32(x, 0x7e) {
72 return false
73 }
74 i += 4
75 }
76
77 var x uint32
78 switch n - i {
79 case 3:
80 x = 0x20000000 | uint32(*(*uint8)(unsafe.Pointer(uintptr(p) + i))) | uint32(*(*uint16)(unsafe.Pointer(uintptr(p) + i + 1)))<<8
81 case 2:
82 x = 0x20200000 | uint32(*(*uint16)(unsafe.Pointer(uintptr(p) + i)))
83 case 1:
84 x = 0x20202000 | uint32(*(*uint8)(unsafe.Pointer(uintptr(p) + i)))
85 default:
86 return true
87 }
88 return !(hasLess32(x, 0x20) || hasMore32(x, 0x7e))
89}
90
91// https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord
92const (
93 hasLessConstL64 = (^uint64(0)) / 255
94 hasLessConstR64 = hasLessConstL64 * 128
95
96 hasLessConstL32 = (^uint32(0)) / 255
97 hasLessConstR32 = hasLessConstL32 * 128
98
99 hasMoreConstL64 = (^uint64(0)) / 255
100 hasMoreConstR64 = hasMoreConstL64 * 128
101
102 hasMoreConstL32 = (^uint32(0)) / 255
103 hasMoreConstR32 = hasMoreConstL32 * 128
104)
105
106//go:nosplit
107func hasLess64(x, n uint64) bool {
108 return ((x - (hasLessConstL64 * n)) & ^x & hasLessConstR64) != 0
109}
110
111//go:nosplit
112func hasLess32(x, n uint32) bool {
113 return ((x - (hasLessConstL32 * n)) & ^x & hasLessConstR32) != 0
114}
115
116//go:nosplit
117func hasMore64(x, n uint64) bool {
118 return (((x + (hasMoreConstL64 * (127 - n))) | x) & hasMoreConstR64) != 0
119}
120
121//go:nosplit
122func hasMore32(x, n uint32) bool {
123 return (((x + (hasMoreConstL32 * (127 - n))) | x) & hasMoreConstR32) != 0
124}