github.com/ethxdao/go-ethereum@v0.0.0-20221218102228-5ae34a9cc189/common/bitutil/bitutil.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Adapted from: https://golang.org/src/crypto/cipher/xor.go 6 7 // Package bitutil implements fast bitwise operations. 8 package bitutil 9 10 import ( 11 "runtime" 12 "unsafe" 13 ) 14 15 const wordSize = int(unsafe.Sizeof(uintptr(0))) 16 const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x" 17 18 // XORBytes xors the bytes in a and b. The destination is assumed to have enough 19 // space. Returns the number of bytes xor'd. 20 func XORBytes(dst, a, b []byte) int { 21 if supportsUnaligned { 22 return fastXORBytes(dst, a, b) 23 } 24 return safeXORBytes(dst, a, b) 25 } 26 27 // fastXORBytes xors in bulk. It only works on architectures that support 28 // unaligned read/writes. 29 func fastXORBytes(dst, a, b []byte) int { 30 n := len(a) 31 if len(b) < n { 32 n = len(b) 33 } 34 w := n / wordSize 35 if w > 0 { 36 dw := *(*[]uintptr)(unsafe.Pointer(&dst)) 37 aw := *(*[]uintptr)(unsafe.Pointer(&a)) 38 bw := *(*[]uintptr)(unsafe.Pointer(&b)) 39 for i := 0; i < w; i++ { 40 dw[i] = aw[i] ^ bw[i] 41 } 42 } 43 for i := n - n%wordSize; i < n; i++ { 44 dst[i] = a[i] ^ b[i] 45 } 46 return n 47 } 48 49 // safeXORBytes xors one by one. It works on all architectures, independent if 50 // it supports unaligned read/writes or not. 51 func safeXORBytes(dst, a, b []byte) int { 52 n := len(a) 53 if len(b) < n { 54 n = len(b) 55 } 56 for i := 0; i < n; i++ { 57 dst[i] = a[i] ^ b[i] 58 } 59 return n 60 } 61 62 // ANDBytes ands the bytes in a and b. The destination is assumed to have enough 63 // space. Returns the number of bytes and'd. 64 func ANDBytes(dst, a, b []byte) int { 65 if supportsUnaligned { 66 return fastANDBytes(dst, a, b) 67 } 68 return safeANDBytes(dst, a, b) 69 } 70 71 // fastANDBytes ands in bulk. It only works on architectures that support 72 // unaligned read/writes. 73 func fastANDBytes(dst, a, b []byte) int { 74 n := len(a) 75 if len(b) < n { 76 n = len(b) 77 } 78 w := n / wordSize 79 if w > 0 { 80 dw := *(*[]uintptr)(unsafe.Pointer(&dst)) 81 aw := *(*[]uintptr)(unsafe.Pointer(&a)) 82 bw := *(*[]uintptr)(unsafe.Pointer(&b)) 83 for i := 0; i < w; i++ { 84 dw[i] = aw[i] & bw[i] 85 } 86 } 87 for i := n - n%wordSize; i < n; i++ { 88 dst[i] = a[i] & b[i] 89 } 90 return n 91 } 92 93 // safeANDBytes ands one by one. It works on all architectures, independent if 94 // it supports unaligned read/writes or not. 95 func safeANDBytes(dst, a, b []byte) int { 96 n := len(a) 97 if len(b) < n { 98 n = len(b) 99 } 100 for i := 0; i < n; i++ { 101 dst[i] = a[i] & b[i] 102 } 103 return n 104 } 105 106 // ORBytes ors the bytes in a and b. The destination is assumed to have enough 107 // space. Returns the number of bytes or'd. 108 func ORBytes(dst, a, b []byte) int { 109 if supportsUnaligned { 110 return fastORBytes(dst, a, b) 111 } 112 return safeORBytes(dst, a, b) 113 } 114 115 // fastORBytes ors in bulk. It only works on architectures that support 116 // unaligned read/writes. 117 func fastORBytes(dst, a, b []byte) int { 118 n := len(a) 119 if len(b) < n { 120 n = len(b) 121 } 122 w := n / wordSize 123 if w > 0 { 124 dw := *(*[]uintptr)(unsafe.Pointer(&dst)) 125 aw := *(*[]uintptr)(unsafe.Pointer(&a)) 126 bw := *(*[]uintptr)(unsafe.Pointer(&b)) 127 for i := 0; i < w; i++ { 128 dw[i] = aw[i] | bw[i] 129 } 130 } 131 for i := n - n%wordSize; i < n; i++ { 132 dst[i] = a[i] | b[i] 133 } 134 return n 135 } 136 137 // safeORBytes ors one by one. It works on all architectures, independent if 138 // it supports unaligned read/writes or not. 139 func safeORBytes(dst, a, b []byte) int { 140 n := len(a) 141 if len(b) < n { 142 n = len(b) 143 } 144 for i := 0; i < n; i++ { 145 dst[i] = a[i] | b[i] 146 } 147 return n 148 } 149 150 // TestBytes tests whether any bit is set in the input byte slice. 151 func TestBytes(p []byte) bool { 152 if supportsUnaligned { 153 return fastTestBytes(p) 154 } 155 return safeTestBytes(p) 156 } 157 158 // fastTestBytes tests for set bits in bulk. It only works on architectures that 159 // support unaligned read/writes. 160 func fastTestBytes(p []byte) bool { 161 n := len(p) 162 w := n / wordSize 163 if w > 0 { 164 pw := *(*[]uintptr)(unsafe.Pointer(&p)) 165 for i := 0; i < w; i++ { 166 if pw[i] != 0 { 167 return true 168 } 169 } 170 } 171 for i := n - n%wordSize; i < n; i++ { 172 if p[i] != 0 { 173 return true 174 } 175 } 176 return false 177 } 178 179 // safeTestBytes tests for set bits one byte at a time. It works on all 180 // architectures, independent if it supports unaligned read/writes or not. 181 func safeTestBytes(p []byte) bool { 182 for i := 0; i < len(p); i++ { 183 if p[i] != 0 { 184 return true 185 } 186 } 187 return false 188 }