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  }