diff --git a/common/bitutil/bitutil.go b/common/bitutil/bitutil.go index a18a6d18eed..86482bb0c77 100644 --- a/common/bitutil/bitutil.go +++ b/common/bitutil/bitutil.go @@ -27,20 +27,29 @@ func XORBytes(dst, a, b []byte) int { // fastXORBytes xors in bulk. It only works on architectures that support // unaligned read/writes. func fastXORBytes(dst, a, b []byte) int { - n := len(a) - if len(b) < n { - n = len(b) + n := min(len(a), len(b), len(dst)) + if n == 0 { + return 0 } - w := n / wordSize + wordSize := int(unsafe.Sizeof(uintptr(0))) + + i := 0 + for ; i < n && uintptr(unsafe.Pointer(&a[i]))%uintptr(wordSize) != 0; i++ { + dst[i] = a[i] ^ b[i] + } + + w := (n - i) / wordSize if w > 0 { - dw := *(*[]uintptr)(unsafe.Pointer(&dst)) - aw := *(*[]uintptr)(unsafe.Pointer(&a)) - bw := *(*[]uintptr)(unsafe.Pointer(&b)) - for i := 0; i < w; i++ { - dw[i] = aw[i] ^ bw[i] + ad := unsafe.Slice((*uintptr)(unsafe.Pointer(&a[i])), w) + bd := unsafe.Slice((*uintptr)(unsafe.Pointer(&b[i])), w) + dd := unsafe.Slice((*uintptr)(unsafe.Pointer(&dst[i])), w) + for j := 0; j < w; j++ { + dd[j] = ad[j] ^ bd[j] } + i += w * wordSize } - for i := n - n%wordSize; i < n; i++ { + + for ; i < n; i++ { dst[i] = a[i] ^ b[i] } return n @@ -49,11 +58,8 @@ func fastXORBytes(dst, a, b []byte) int { // safeXORBytes xors one by one. It works on all architectures, independent if // it supports unaligned read/writes or not. func safeXORBytes(dst, a, b []byte) int { - n := len(a) - if len(b) < n { - n = len(b) - } - for i := 0; i < n; i++ { + n := min(len(b), len(a)) + for i := range n { dst[i] = a[i] ^ b[i] } return n @@ -71,20 +77,29 @@ func ANDBytes(dst, a, b []byte) int { // fastANDBytes ands in bulk. It only works on architectures that support // unaligned read/writes. func fastANDBytes(dst, a, b []byte) int { - n := len(a) - if len(b) < n { - n = len(b) + n := min(len(a), len(b), len(dst)) + if n == 0 { + return 0 } - w := n / wordSize + wordSize := int(unsafe.Sizeof(uintptr(0))) + + i := 0 + for ; i < n && uintptr(unsafe.Pointer(&a[i]))%uintptr(wordSize) != 0; i++ { + dst[i] = a[i] & b[i] + } + + w := (n - i) / wordSize if w > 0 { - dw := *(*[]uintptr)(unsafe.Pointer(&dst)) - aw := *(*[]uintptr)(unsafe.Pointer(&a)) - bw := *(*[]uintptr)(unsafe.Pointer(&b)) - for i := 0; i < w; i++ { - dw[i] = aw[i] & bw[i] + ad := unsafe.Slice((*uintptr)(unsafe.Pointer(&a[i])), w) + bd := unsafe.Slice((*uintptr)(unsafe.Pointer(&b[i])), w) + dd := unsafe.Slice((*uintptr)(unsafe.Pointer(&dst[i])), w) + for j := 0; j < w; j++ { + dd[j] = ad[j] & bd[j] } + i += w * wordSize } - for i := n - n%wordSize; i < n; i++ { + + for ; i < n; i++ { dst[i] = a[i] & b[i] } return n @@ -93,11 +108,8 @@ func fastANDBytes(dst, a, b []byte) int { // safeANDBytes ands one by one. It works on all architectures, independent if // it supports unaligned read/writes or not. func safeANDBytes(dst, a, b []byte) int { - n := len(a) - if len(b) < n { - n = len(b) - } - for i := 0; i < n; i++ { + n := min(len(b), len(a)) + for i := range n { dst[i] = a[i] & b[i] } return n @@ -115,20 +127,29 @@ func ORBytes(dst, a, b []byte) int { // fastORBytes ors in bulk. It only works on architectures that support // unaligned read/writes. func fastORBytes(dst, a, b []byte) int { - n := len(a) - if len(b) < n { - n = len(b) + n := min(len(a), len(b), len(dst)) + if n == 0 { + return 0 } - w := n / wordSize + wordSize := int(unsafe.Sizeof(uintptr(0))) + + i := 0 + for ; i < n && uintptr(unsafe.Pointer(&a[i]))%uintptr(wordSize) != 0; i++ { + dst[i] = a[i] | b[i] + } + + w := (n - i) / wordSize if w > 0 { - dw := *(*[]uintptr)(unsafe.Pointer(&dst)) - aw := *(*[]uintptr)(unsafe.Pointer(&a)) - bw := *(*[]uintptr)(unsafe.Pointer(&b)) - for i := 0; i < w; i++ { - dw[i] = aw[i] | bw[i] + ad := unsafe.Slice((*uintptr)(unsafe.Pointer(&a[i])), w) + bd := unsafe.Slice((*uintptr)(unsafe.Pointer(&b[i])), w) + dd := unsafe.Slice((*uintptr)(unsafe.Pointer(&dst[i])), w) + for j := 0; j < w; j++ { + dd[j] = ad[j] | bd[j] } + i += w * wordSize } - for i := n - n%wordSize; i < n; i++ { + + for ; i < n; i++ { dst[i] = a[i] | b[i] } return n @@ -137,10 +158,7 @@ func fastORBytes(dst, a, b []byte) int { // safeORBytes ors one by one. It works on all architectures, independent if // it supports unaligned read/writes or not. func safeORBytes(dst, a, b []byte) int { - n := len(a) - if len(b) < n { - n = len(b) - } + n := min(len(b), len(a)) for i := 0; i < n; i++ { dst[i] = a[i] | b[i] } @@ -179,7 +197,7 @@ func fastTestBytes(p []byte) bool { // safeTestBytes tests for set bits one byte at a time. It works on all // architectures, independent if it supports unaligned read/writes or not. func safeTestBytes(p []byte) bool { - for i := 0; i < len(p); i++ { + for i := range p { if p[i] != 0 { return true } diff --git a/common/bytes.go b/common/bytes.go index d1f5c6c9958..b3438c177d2 100644 --- a/common/bytes.go +++ b/common/bytes.go @@ -52,22 +52,13 @@ func has0xPrefix(str string) bool { return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X') } -// isHexCharacter returns bool of c being a valid hexadecimal. -func isHexCharacter(c byte) bool { - return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F') -} - // isHex validates whether each byte is valid hexadecimal string. func isHex(str string) bool { if len(str)%2 != 0 { return false } - for _, c := range []byte(str) { - if !isHexCharacter(c) { - return false - } - } - return true + _, err := hex.DecodeString(str) + return err == nil } // Bytes2Hex returns the hexadecimal encoding of d.