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}