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