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 }