github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/common/bitutil/bitutil.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 // Adapted from: https://golang.org/src/crypto/cipher/xor.go 19 20 // Package bitutil implements fast bitwise operations. 21 package bitutil 22 23 import ( 24 "runtime" 25 "unsafe" 26 ) 27 28 const wordSize = int(unsafe.Sizeof(uintptr(0))) 29 const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x" 30 31 // XORBytes xors the bytes in a and b. The destination is assumed to have enough 32 // space. Returns the number of bytes xor'd. 33 func XORBytes(dst, a, b []byte) int { 34 if supportsUnaligned { 35 return fastXORBytes(dst, a, b) 36 } 37 return safeXORBytes(dst, a, b) 38 } 39 40 // fastXORBytes xors in bulk. It only works on architectures that support 41 // unaligned read/writes. 42 func fastXORBytes(dst, a, b []byte) int { 43 n := len(a) 44 if len(b) < n { 45 n = len(b) 46 } 47 w := n / wordSize 48 if w > 0 { 49 dw := *(*[]uintptr)(unsafe.Pointer(&dst)) 50 aw := *(*[]uintptr)(unsafe.Pointer(&a)) 51 bw := *(*[]uintptr)(unsafe.Pointer(&b)) 52 for i := 0; i < w; i++ { 53 dw[i] = aw[i] ^ bw[i] 54 } 55 } 56 for i := n - n%wordSize; i < n; i++ { 57 dst[i] = a[i] ^ b[i] 58 } 59 return n 60 } 61 62 // safeXORBytes xors one by one. It works on all architectures, independent if 63 // it supports unaligned read/writes or not. 64 func safeXORBytes(dst, a, b []byte) int { 65 n := len(a) 66 if len(b) < n { 67 n = len(b) 68 } 69 for i := 0; i < n; i++ { 70 dst[i] = a[i] ^ b[i] 71 } 72 return n 73 } 74 75 // ANDBytes ands the bytes in a and b. The destination is assumed to have enough 76 // space. Returns the number of bytes and'd. 77 func ANDBytes(dst, a, b []byte) int { 78 if supportsUnaligned { 79 return fastANDBytes(dst, a, b) 80 } 81 return safeANDBytes(dst, a, b) 82 } 83 84 // fastANDBytes ands in bulk. It only works on architectures that support 85 // unaligned read/writes. 86 func fastANDBytes(dst, a, b []byte) int { 87 n := len(a) 88 if len(b) < n { 89 n = len(b) 90 } 91 w := n / wordSize 92 if w > 0 { 93 dw := *(*[]uintptr)(unsafe.Pointer(&dst)) 94 aw := *(*[]uintptr)(unsafe.Pointer(&a)) 95 bw := *(*[]uintptr)(unsafe.Pointer(&b)) 96 for i := 0; i < w; i++ { 97 dw[i] = aw[i] & bw[i] 98 } 99 } 100 for i := n - n%wordSize; i < n; i++ { 101 dst[i] = a[i] & b[i] 102 } 103 return n 104 } 105 106 // safeANDBytes ands one by one. It works on all architectures, independent if 107 // it supports unaligned read/writes or not. 108 func safeANDBytes(dst, a, b []byte) int { 109 n := len(a) 110 if len(b) < n { 111 n = len(b) 112 } 113 for i := 0; i < n; i++ { 114 dst[i] = a[i] & b[i] 115 } 116 return n 117 } 118 119 // ORBytes ors the bytes in a and b. The destination is assumed to have enough 120 // space. Returns the number of bytes or'd. 121 func ORBytes(dst, a, b []byte) int { 122 if supportsUnaligned { 123 return fastORBytes(dst, a, b) 124 } 125 return safeORBytes(dst, a, b) 126 } 127 128 // fastORBytes ors in bulk. It only works on architectures that support 129 // unaligned read/writes. 130 func fastORBytes(dst, a, b []byte) int { 131 n := len(a) 132 if len(b) < n { 133 n = len(b) 134 } 135 w := n / wordSize 136 if w > 0 { 137 dw := *(*[]uintptr)(unsafe.Pointer(&dst)) 138 aw := *(*[]uintptr)(unsafe.Pointer(&a)) 139 bw := *(*[]uintptr)(unsafe.Pointer(&b)) 140 for i := 0; i < w; i++ { 141 dw[i] = aw[i] | bw[i] 142 } 143 } 144 for i := n - n%wordSize; i < n; i++ { 145 dst[i] = a[i] | b[i] 146 } 147 return n 148 } 149 150 // safeORBytes ors one by one. It works on all architectures, independent if 151 // it supports unaligned read/writes or not. 152 func safeORBytes(dst, a, b []byte) int { 153 n := len(a) 154 if len(b) < n { 155 n = len(b) 156 } 157 for i := 0; i < n; i++ { 158 dst[i] = a[i] | b[i] 159 } 160 return n 161 } 162 163 // TestBytes tests whether any bit is set in the input byte slice. 164 func TestBytes(p []byte) bool { 165 if supportsUnaligned { 166 return fastTestBytes(p) 167 } 168 return safeTestBytes(p) 169 } 170 171 // fastTestBytes tests for set bits in bulk. It only works on architectures that 172 // support unaligned read/writes. 173 func fastTestBytes(p []byte) bool { 174 n := len(p) 175 w := n / wordSize 176 if w > 0 { 177 pw := *(*[]uintptr)(unsafe.Pointer(&p)) 178 for i := 0; i < w; i++ { 179 if pw[i] != 0 { 180 return true 181 } 182 } 183 } 184 for i := n - n%wordSize; i < n; i++ { 185 if p[i] != 0 { 186 return true 187 } 188 } 189 return false 190 } 191 192 // safeTestBytes tests for set bits one byte at a time. It works on all 193 // architectures, independent if it supports unaligned read/writes or not. 194 func safeTestBytes(p []byte) bool { 195 for i := 0; i < len(p); i++ { 196 if p[i] != 0 { 197 return true 198 } 199 } 200 return false 201 }