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  }