github.com/neilotoole/jsoncolor@v0.7.2-0.20231115150201-1637fae69be1/ascii.go (about) 1 package jsoncolor 2 3 import "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 10 func 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 51 func 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 92 const ( 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 107 func hasLess64(x, n uint64) bool { 108 return ((x - (hasLessConstL64 * n)) & ^x & hasLessConstR64) != 0 109 } 110 111 //go:nosplit 112 func hasLess32(x, n uint32) bool { 113 return ((x - (hasLessConstL32 * n)) & ^x & hasLessConstR32) != 0 114 } 115 116 //go:nosplit 117 func hasMore64(x, n uint64) bool { 118 return (((x + (hasMoreConstL64 * (127 - n))) | x) & hasMoreConstR64) != 0 119 } 120 121 //go:nosplit 122 func hasMore32(x, n uint32) bool { 123 return (((x + (hasMoreConstL32 * (127 - n))) | x) & hasMoreConstR32) != 0 124 }