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  }