github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/common/bitutil/bitutil.go (about)

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