summaryrefslogtreecommitdiff
path: root/vendor/github.com/templexxx/xorsimd/xor_generic.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/templexxx/xorsimd/xor_generic.go')
-rw-r--r--vendor/github.com/templexxx/xorsimd/xor_generic.go205
1 files changed, 205 insertions, 0 deletions
diff --git a/vendor/github.com/templexxx/xorsimd/xor_generic.go b/vendor/github.com/templexxx/xorsimd/xor_generic.go
new file mode 100644
index 0000000..b12908f
--- /dev/null
+++ b/vendor/github.com/templexxx/xorsimd/xor_generic.go
@@ -0,0 +1,205 @@
+// Copyright (c) 2019. Temple3x (temple3x@gmail.com)
+//
+// Use of this source code is governed by the MIT License
+// that can be found in the LICENSE file.
+//
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64
+
+package xorsimd
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+const wordSize = int(unsafe.Sizeof(uintptr(0)))
+const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x"
+
+func encode(dst []byte, src [][]byte) {
+ if supportsUnaligned {
+ fastEncode(dst, src, len(dst))
+ } else {
+ // TODO(hanwen): if (dst, a, b) have common alignment
+ // we could still try fastEncode. It is not clear
+ // how often this happens, and it's only worth it if
+ // the block encryption itself is hardware
+ // accelerated.
+ safeEncode(dst, src, len(dst))
+ }
+
+}
+
+// fastEncode xor in bulk. It only works on architectures that
+// support unaligned read/writes.
+func fastEncode(dst []byte, src [][]byte, n int) {
+ w := n / wordSize
+ if w > 0 {
+ wordBytes := w * wordSize
+
+ wordAlignSrc := make([][]byte, len(src))
+ for i := range src {
+ wordAlignSrc[i] = src[i][:wordBytes]
+ }
+ fastEnc(dst[:wordBytes], wordAlignSrc)
+ }
+
+ for i := n - n%wordSize; i < n; i++ {
+ s := src[0][i]
+ for j := 1; j < len(src); j++ {
+ s ^= src[j][i]
+ }
+ dst[i] = s
+ }
+}
+
+func fastEnc(dst []byte, src [][]byte) {
+ dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+ sw := make([][]uintptr, len(src))
+ for i := range src {
+ sw[i] = *(*[]uintptr)(unsafe.Pointer(&src[i]))
+ }
+
+ n := len(dst) / wordSize
+ for i := 0; i < n; i++ {
+ s := sw[0][i]
+ for j := 1; j < len(sw); j++ {
+ s ^= sw[j][i]
+ }
+ dw[i] = s
+ }
+}
+
+func safeEncode(dst []byte, src [][]byte, n int) {
+ for i := 0; i < n; i++ {
+ s := src[0][i]
+ for j := 1; j < len(src); j++ {
+ s ^= src[j][i]
+ }
+ dst[i] = s
+ }
+}
+
+// Bytes8 XORs of word 8 Bytes.
+// The slice arguments a, b, dst's lengths are assumed to be at least 8,
+// if not, Bytes8 will panic.
+func Bytes8(dst, a, b []byte) {
+
+ bytesWords(dst[:8], a[:8], b[:8])
+}
+
+// Bytes16 XORs of packed doubleword 16 Bytes.
+// The slice arguments a, b, dst's lengths are assumed to be at least 16,
+// if not, Bytes16 will panic.
+func Bytes16(dst, a, b []byte) {
+
+ bytesWords(dst[:16], a[:16], b[:16])
+}
+
+// bytesWords XORs multiples of 4 or 8 bytes (depending on architecture.)
+// The slice arguments a and b are assumed to be of equal length.
+func bytesWords(dst, a, b []byte) {
+ if supportsUnaligned {
+ dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+ aw := *(*[]uintptr)(unsafe.Pointer(&a))
+ bw := *(*[]uintptr)(unsafe.Pointer(&b))
+ n := len(b) / wordSize
+ for i := 0; i < n; i++ {
+ dw[i] = aw[i] ^ bw[i]
+ }
+ } else {
+ n := len(b)
+ for i := 0; i < n; i++ {
+ dst[i] = a[i] ^ b[i]
+ }
+ }
+}
+
+// Bytes8Align XORs of 8 Bytes.
+// The slice arguments a, b, dst's lengths are assumed to be at least 8,
+// if not, Bytes8 will panic.
+//
+// All the byte slices must be aligned to wordsize.
+func Bytes8Align(dst, a, b []byte) {
+
+ bytesWordsAlign(dst[:8], a[:8], b[:8])
+}
+
+// Bytes16Align XORs of packed 16 Bytes.
+// The slice arguments a, b, dst's lengths are assumed to be at least 16,
+// if not, Bytes16 will panic.
+//
+// All the byte slices must be aligned to wordsize.
+func Bytes16Align(dst, a, b []byte) {
+
+ bytesWordsAlign(dst[:16], a[:16], b[:16])
+}
+
+// bytesWordsAlign XORs multiples of 4 or 8 bytes (depending on architecture.)
+// The slice arguments a and b are assumed to be of equal length.
+//
+// All the byte slices must be aligned to wordsize.
+func bytesWordsAlign(dst, a, b []byte) {
+ dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+ aw := *(*[]uintptr)(unsafe.Pointer(&a))
+ bw := *(*[]uintptr)(unsafe.Pointer(&b))
+ n := len(b) / wordSize
+ for i := 0; i < n; i++ {
+ dw[i] = aw[i] ^ bw[i]
+ }
+}
+
+// BytesA XORs the len(a) bytes in a and b into a
+// destination slice.
+// The destination should have enough space.
+//
+// It's used for encoding small bytes slices (< dozens bytes),
+// and the slices may not be aligned to 8 bytes or 16 bytes.
+// If the length is big, it's better to use 'func Bytes(dst, a, b []byte)' instead
+// for gain better performance.
+func BytesA(dst, a, b []byte) {
+
+ n := len(a)
+ bytesN(dst[:n], a[:n], b[:n], n)
+}
+
+// BytesB XORs the len(b) bytes in a and b into a
+// destination slice.
+// The destination should have enough space.
+//
+// It's used for encoding small bytes slices (< dozens bytes),
+// and the slices may not be aligned to 8 bytes or 16 bytes.
+// If the length is big, it's better to use 'func Bytes(dst, a, b []byte)' instead
+// for gain better performance.
+func BytesB(dst, a, b []byte) {
+
+ n := len(b)
+ bytesN(dst[:n], a[:n], b[:n], n)
+}
+
+func bytesN(dst, a, b []byte, n int) {
+
+ switch {
+ case supportsUnaligned:
+ w := n / 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]
+ }
+ }
+
+ for i := (n - n%wordSize); i < n; i++ {
+ dst[i] = a[i] ^ b[i]
+ }
+ default:
+ for i := 0; i < n; i++ {
+ dst[i] = a[i] ^ b[i]
+ }
+ }
+}