github.com/tunabay/go-bitarray@v1.3.1/bitarray_bitwise.go (about)

     1  // Copyright (c) 2021 Hirotsuna Mizuno. All rights reserved.
     2  // Use of this source code is governed by the MIT license that can be found in
     3  // the LICENSE file.
     4  
     5  package bitarray
     6  
     7  import (
     8  	"math/bits"
     9  )
    10  
    11  // LeadingZeros returns the number of leading zero bits in the BitArray.
    12  func (ba *BitArray) LeadingZeros() int {
    13  	switch {
    14  	case ba.IsZero():
    15  		return 0
    16  	case ba.b == nil:
    17  		return ba.nBits
    18  	}
    19  	n := 0
    20  	nb := ba.nBits >> 3
    21  	for i := 0; i < nb; i++ {
    22  		z := bits.LeadingZeros8(ba.b[i])
    23  		n += z
    24  		if z != 8 {
    25  			return n
    26  		}
    27  	}
    28  
    29  	fb := ba.nBits & 7
    30  	if fb == 0 {
    31  		return n
    32  	}
    33  	z := bits.LeadingZeros8(ba.b[nb])
    34  	if fb < z {
    35  		z = fb
    36  	}
    37  
    38  	return n + z
    39  }
    40  
    41  // TrailingZeros returns the number of trailing zero bits in the BitArray.
    42  func (ba *BitArray) TrailingZeros() int {
    43  	switch {
    44  	case ba.IsZero():
    45  		return 0
    46  	case ba.b == nil:
    47  		return ba.nBits
    48  	}
    49  	n := 0
    50  	for i := len(ba.b) - 1; 0 <= i; i-- {
    51  		z := bits.TrailingZeros8(ba.b[i])
    52  		n += z
    53  		if z != 8 {
    54  			return n - ba.NumPadding()
    55  		}
    56  	}
    57  
    58  	return n - ba.NumPadding()
    59  }
    60  
    61  func (ba *BitArray) hasTrailingZeros(n int) bool {
    62  	if n == 0 {
    63  		return true
    64  	}
    65  	n += ba.NumPadding()
    66  
    67  	for i := len(ba.b) - 1; 0 <= i; i-- {
    68  		z := bits.TrailingZeros8(ba.b[i])
    69  		n -= z
    70  		switch {
    71  		case n <= 0:
    72  			return true
    73  		case z != 8:
    74  			return false
    75  		}
    76  	}
    77  	return false
    78  }
    79  
    80  // OnesCount returns the number of one bits, population count, in the BitArray.
    81  func (ba *BitArray) OnesCount() int {
    82  	if ba.IsZero() || ba.b == nil {
    83  		return 0
    84  	}
    85  	n := 0
    86  	for _, u64 := range asUint64Slice(ba.b) {
    87  		n += bits.OnesCount64(u64)
    88  	}
    89  
    90  	return n
    91  }
    92  
    93  // And returns a new BitArray as a result of a bitwise AND with x. The ba and x
    94  // must be the same length, otherwise And will panic. Use AndAt instead to apply
    95  // a partial AND with a short bit array.
    96  func (ba *BitArray) And(x BitArrayer) *BitArray {
    97  	var bax *BitArray
    98  	if x != nil {
    99  		bax = x.BitArray()
   100  	}
   101  	baLen, xLen := ba.Len(), bax.Len()
   102  	switch {
   103  	case baLen != xLen:
   104  		panicf("And: length is not the same: %d != %d.", baLen, xLen)
   105  	case baLen == 0:
   106  		return zeroBitArray
   107  	case ba.b == nil:
   108  		return ba
   109  	case bax.b == nil:
   110  		return bax
   111  	}
   112  	zv := uint64(0)
   113  	buf := allocByteSlice(len(ba.b))
   114  	buf64 := asUint64Slice(buf)
   115  	x64 := asUint64Slice(bax.b)
   116  	for i, u64 := range asUint64Slice(ba.b) {
   117  		buf64[i] = u64 & x64[i]
   118  		zv |= buf64[i]
   119  	}
   120  	if zv == 0 {
   121  		return &BitArray{nBits: ba.nBits}
   122  	}
   123  	return &BitArray{b: buf, nBits: ba.nBits}
   124  }
   125  
   126  // Or returns a new BitArray as a result of a bitwise OR with x. The ba and x
   127  // must be the same length, otherwise Or will panic. Use OrAt instead to apply a
   128  // partial OR with a short bit array.
   129  func (ba *BitArray) Or(x BitArrayer) *BitArray {
   130  	var bax *BitArray
   131  	if x != nil {
   132  		bax = x.BitArray()
   133  	}
   134  	baLen, xLen := ba.Len(), bax.Len()
   135  	switch {
   136  	case baLen != xLen:
   137  		panicf("Or: length is not the same: %d != %d.", baLen, xLen)
   138  	case baLen == 0:
   139  		return zeroBitArray
   140  	case ba.b == nil:
   141  		return bax
   142  	case bax.b == nil:
   143  		return ba
   144  	}
   145  	zv := uint64(0)
   146  	buf := allocByteSlice(len(ba.b))
   147  	buf64 := asUint64Slice(buf)
   148  	x64 := asUint64Slice(bax.b)
   149  	for i, u64 := range asUint64Slice(ba.b) {
   150  		buf64[i] = u64 | x64[i]
   151  		zv |= buf64[i]
   152  	}
   153  	if zv == 0 {
   154  		return &BitArray{nBits: ba.nBits}
   155  	}
   156  	return &BitArray{b: buf, nBits: ba.nBits}
   157  }
   158  
   159  // Xor returns a new BitArray as a result of a bitwise XOR with x. The ba and x
   160  // must be the same length, otherwise Xor will panic. Use XorAt instead to apply
   161  // a partial XOR with a short bit array.
   162  func (ba *BitArray) Xor(x BitArrayer) *BitArray {
   163  	var bax *BitArray
   164  	if x != nil {
   165  		bax = x.BitArray()
   166  	}
   167  	baLen, xLen := ba.Len(), bax.Len()
   168  	switch {
   169  	case baLen != xLen:
   170  		panicf("Xor: length is not the same: %d != %d.", baLen, xLen)
   171  	case baLen == 0:
   172  		return zeroBitArray
   173  	case ba.b == nil:
   174  		return bax
   175  	case bax.b == nil:
   176  		return ba
   177  	}
   178  	zv := uint64(0)
   179  	buf := allocByteSlice(len(ba.b))
   180  	buf64 := asUint64Slice(buf)
   181  	x64 := asUint64Slice(bax.b)
   182  	for i, u64 := range asUint64Slice(ba.b) {
   183  		buf64[i] = u64 ^ x64[i]
   184  		zv |= buf64[i]
   185  	}
   186  	if zv == 0 {
   187  		return &BitArray{nBits: ba.nBits}
   188  	}
   189  	return &BitArray{b: buf, nBits: ba.nBits}
   190  }
   191  
   192  // Not returns a new BitArray that is the result of inverting all the bits.
   193  func (ba *BitArray) Not() *BitArray {
   194  	switch {
   195  	case ba.IsZero():
   196  		return zeroBitArray
   197  	case ba.b == nil:
   198  		return NewOneFilled(ba.nBits)
   199  	}
   200  	// TODO: use asUint64Slice()
   201  	zv := byte(0)
   202  	buf := allocByteSlice(len(ba.b))
   203  	for i := 0; i < len(buf)-1; i++ {
   204  		buf[i] = ^ba.b[i]
   205  		zv |= buf[i]
   206  	}
   207  	buf[len(buf)-1] = ^ba.b[len(ba.b)-1] & (byte(0xff) << ba.NumPadding())
   208  	zv |= buf[len(buf)-1]
   209  	if zv == 0 {
   210  		return &BitArray{nBits: ba.nBits}
   211  	}
   212  	return &BitArray{b: buf, nBits: ba.nBits}
   213  }
   214  
   215  // AndAt returns a new BitArray resulting from applying a bitwise AND operation
   216  // with x at the offset off. AND is applied only to the range from off to
   217  // off+x.Len(), and other bits are preserved.
   218  func (ba *BitArray) AndAt(off int, x BitArrayer) *BitArray {
   219  	var bax *BitArray
   220  	if x != nil {
   221  		bax = x.BitArray()
   222  	}
   223  	baLen, xLen := ba.Len(), bax.Len()
   224  	switch {
   225  	case off < 0:
   226  		panicf("AndAt: negative off %d.", off)
   227  	case baLen < off+xLen:
   228  		panicf("AndAt: out of range: off=%d + x.len=%d > len=%d.", off, xLen, baLen)
   229  	case baLen == 0:
   230  		return zeroBitArray
   231  	case ba.b == nil:
   232  		return ba
   233  	case bax.b == nil:
   234  		buf := allocByteSlice(len(ba.b))
   235  		copy(buf, ba.b)
   236  		clearBits(buf, off, xLen)
   237  		return &BitArray{b: buf, nBits: baLen}
   238  	}
   239  	buf := allocByteSlice(len(ba.b))
   240  	copy(buf, ba.b)
   241  	andBits(buf, bax.b, off, 0, xLen)
   242  	return &BitArray{b: buf, nBits: baLen}
   243  }
   244  
   245  // OrAt returns a new BitArray resulting from applying a bitwise OR operation
   246  // with x at the offset off. OR is applied only to the range from off to
   247  // off+x.Len(), and other bits are preserved.
   248  func (ba *BitArray) OrAt(off int, x BitArrayer) *BitArray {
   249  	var bax *BitArray
   250  	if x != nil {
   251  		bax = x.BitArray()
   252  	}
   253  	baLen, xLen := ba.Len(), bax.Len()
   254  	switch {
   255  	case off < 0:
   256  		panicf("OrAt: negative off %d.", off)
   257  	case baLen < off+xLen:
   258  		panicf("OrAt: out of range: off=%d + x.len=%d > len=%d.", off, xLen, baLen)
   259  	case baLen == 0:
   260  		return zeroBitArray
   261  	case bax.b == nil:
   262  		return ba
   263  	case ba.b == nil:
   264  		buf := allocByteSlice((baLen + 7) >> 3)
   265  		_ = copyBits(buf, bax.b, off, 0, xLen)
   266  		return &BitArray{b: buf, nBits: baLen}
   267  	}
   268  	buf := allocByteSlice(len(ba.b))
   269  	copy(buf, ba.b)
   270  	orBits(buf, bax.b, off, 0, xLen)
   271  	return &BitArray{b: buf, nBits: baLen}
   272  }
   273  
   274  // XorAt returns a new BitArray resulting from applying a bitwise XOR operation
   275  // with x at the offset off. XOR is applied only to the range from off to
   276  // off+x.Len(), and other bits are preserved.
   277  func (ba *BitArray) XorAt(off int, x BitArrayer) *BitArray {
   278  	var bax *BitArray
   279  	if x != nil {
   280  		bax = x.BitArray()
   281  	}
   282  	baLen, xLen := ba.Len(), bax.Len()
   283  	switch {
   284  	case off < 0:
   285  		panicf("XorAt: negative off %d.", off)
   286  	case baLen < off+xLen:
   287  		panicf("XorAt: out of range: off=%d + x.len=%d > len=%d", off, xLen, baLen)
   288  	case baLen == 0:
   289  		return zeroBitArray
   290  	case bax.b == nil:
   291  		return ba
   292  	case ba.b == nil:
   293  		buf := allocByteSlice((baLen + 7) >> 3)
   294  		_ = copyBits(buf, bax.b, off, 0, xLen)
   295  		return &BitArray{b: buf, nBits: baLen}
   296  	}
   297  	buf := allocByteSlice(len(ba.b))
   298  	copy(buf, ba.b)
   299  	xorBits(buf, bax.b, off, 0, xLen)
   300  	return &BitArray{b: buf, nBits: baLen}
   301  }