github.com/supragya/TendermintConnector@v0.0.0-20210619045051-113e32b84fb1/_deprecated_chains/cosmos/libs/common/bit_array.go (about) 1 package common 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "regexp" 7 "strings" 8 "sync" 9 ) 10 11 // BitArray is a thread-safe implementation of a bit array. 12 type BitArray struct { 13 mtx sync.Mutex 14 Bits int `json:"bits"` // NOTE: persisted via reflect, must be exported 15 Elems []uint64 `json:"elems"` // NOTE: persisted via reflect, must be exported 16 } 17 18 // NewBitArray returns a new bit array. 19 // It returns nil if the number of bits is zero. 20 func NewBitArray(bits int) *BitArray { 21 if bits <= 0 { 22 return nil 23 } 24 return &BitArray{ 25 Bits: bits, 26 Elems: make([]uint64, (bits+63)/64), 27 } 28 } 29 30 // Size returns the number of bits in the bitarray 31 func (bA *BitArray) Size() int { 32 if bA == nil { 33 return 0 34 } 35 return bA.Bits 36 } 37 38 // GetIndex returns the bit at index i within the bit array. 39 // The behavior is undefined if i >= bA.Bits 40 func (bA *BitArray) GetIndex(i int) bool { 41 if bA == nil { 42 return false 43 } 44 bA.mtx.Lock() 45 defer bA.mtx.Unlock() 46 return bA.getIndex(i) 47 } 48 49 func (bA *BitArray) getIndex(i int) bool { 50 if i >= bA.Bits { 51 return false 52 } 53 return bA.Elems[i/64]&(uint64(1)<<uint(i%64)) > 0 54 } 55 56 // SetIndex sets the bit at index i within the bit array. 57 // The behavior is undefined if i >= bA.Bits 58 func (bA *BitArray) SetIndex(i int, v bool) bool { 59 if bA == nil { 60 return false 61 } 62 bA.mtx.Lock() 63 defer bA.mtx.Unlock() 64 return bA.setIndex(i, v) 65 } 66 67 func (bA *BitArray) setIndex(i int, v bool) bool { 68 if i >= bA.Bits { 69 return false 70 } 71 if v { 72 bA.Elems[i/64] |= (uint64(1) << uint(i%64)) 73 } else { 74 bA.Elems[i/64] &= ^(uint64(1) << uint(i%64)) 75 } 76 return true 77 } 78 79 // Copy returns a copy of the provided bit array. 80 func (bA *BitArray) Copy() *BitArray { 81 if bA == nil { 82 return nil 83 } 84 bA.mtx.Lock() 85 defer bA.mtx.Unlock() 86 return bA.copy() 87 } 88 89 func (bA *BitArray) copy() *BitArray { 90 c := make([]uint64, len(bA.Elems)) 91 copy(c, bA.Elems) 92 return &BitArray{ 93 Bits: bA.Bits, 94 Elems: c, 95 } 96 } 97 98 func (bA *BitArray) copyBits(bits int) *BitArray { 99 c := make([]uint64, (bits+63)/64) 100 copy(c, bA.Elems) 101 return &BitArray{ 102 Bits: bits, 103 Elems: c, 104 } 105 } 106 107 // Or returns a bit array resulting from a bitwise OR of the two bit arrays. 108 // If the two bit-arrys have different lengths, Or right-pads the smaller of the two bit-arrays with zeroes. 109 // Thus the size of the return value is the maximum of the two provided bit arrays. 110 func (bA *BitArray) Or(o *BitArray) *BitArray { 111 if bA == nil && o == nil { 112 return nil 113 } 114 if bA == nil && o != nil { 115 return o.Copy() 116 } 117 if o == nil { 118 return bA.Copy() 119 } 120 bA.mtx.Lock() 121 o.mtx.Lock() 122 c := bA.copyBits(MaxInt(bA.Bits, o.Bits)) 123 smaller := MinInt(len(bA.Elems), len(o.Elems)) 124 for i := 0; i < smaller; i++ { 125 c.Elems[i] |= o.Elems[i] 126 } 127 bA.mtx.Unlock() 128 o.mtx.Unlock() 129 return c 130 } 131 132 // And returns a bit array resulting from a bitwise AND of the two bit arrays. 133 // If the two bit-arrys have different lengths, this truncates the larger of the two bit-arrays from the right. 134 // Thus the size of the return value is the minimum of the two provided bit arrays. 135 func (bA *BitArray) And(o *BitArray) *BitArray { 136 if bA == nil || o == nil { 137 return nil 138 } 139 bA.mtx.Lock() 140 o.mtx.Lock() 141 defer func() { 142 bA.mtx.Unlock() 143 o.mtx.Unlock() 144 }() 145 return bA.and(o) 146 } 147 148 func (bA *BitArray) and(o *BitArray) *BitArray { 149 c := bA.copyBits(MinInt(bA.Bits, o.Bits)) 150 for i := 0; i < len(c.Elems); i++ { 151 c.Elems[i] &= o.Elems[i] 152 } 153 return c 154 } 155 156 // Not returns a bit array resulting from a bitwise Not of the provided bit array. 157 func (bA *BitArray) Not() *BitArray { 158 if bA == nil { 159 return nil // Degenerate 160 } 161 bA.mtx.Lock() 162 defer bA.mtx.Unlock() 163 return bA.not() 164 } 165 166 func (bA *BitArray) not() *BitArray { 167 c := bA.copy() 168 for i := 0; i < len(c.Elems); i++ { 169 c.Elems[i] = ^c.Elems[i] 170 } 171 return c 172 } 173 174 // Sub subtracts the two bit-arrays bitwise, without carrying the bits. 175 // Note that carryless subtraction of a - b is (a and not b). 176 // The output is the same as bA, regardless of o's size. 177 // If bA is longer than o, o is right padded with zeroes 178 func (bA *BitArray) Sub(o *BitArray) *BitArray { 179 if bA == nil || o == nil { 180 return nil 181 } 182 bA.mtx.Lock() 183 o.mtx.Lock() 184 // output is the same size as bA 185 c := bA.copyBits(bA.Bits) 186 // Only iterate to the minimum size between the two. 187 // If o is longer, those bits are ignored. 188 // If bA is longer, then skipping those iterations is equivalent 189 // to right padding with 0's 190 smaller := MinInt(len(bA.Elems), len(o.Elems)) 191 for i := 0; i < smaller; i++ { 192 // &^ is and not in golang 193 c.Elems[i] &^= o.Elems[i] 194 } 195 bA.mtx.Unlock() 196 o.mtx.Unlock() 197 return c 198 } 199 200 // IsEmpty returns true iff all bits in the bit array are 0 201 func (bA *BitArray) IsEmpty() bool { 202 if bA == nil { 203 return true // should this be opposite? 204 } 205 bA.mtx.Lock() 206 defer bA.mtx.Unlock() 207 for _, e := range bA.Elems { 208 if e > 0 { 209 return false 210 } 211 } 212 return true 213 } 214 215 // IsFull returns true iff all bits in the bit array are 1. 216 func (bA *BitArray) IsFull() bool { 217 if bA == nil { 218 return true 219 } 220 bA.mtx.Lock() 221 defer bA.mtx.Unlock() 222 223 // Check all elements except the last 224 for _, elem := range bA.Elems[:len(bA.Elems)-1] { 225 if (^elem) != 0 { 226 return false 227 } 228 } 229 230 // Check that the last element has (lastElemBits) 1's 231 lastElemBits := (bA.Bits+63)%64 + 1 232 lastElem := bA.Elems[len(bA.Elems)-1] 233 return (lastElem+1)&((uint64(1)<<uint(lastElemBits))-1) == 0 234 } 235 236 // PickRandom returns a random index for a set bit in the bit array. 237 // If there is no such value, it returns 0, false. 238 // It uses the global randomness in `random.go` to get this index. 239 func (bA *BitArray) PickRandom() (int, bool) { 240 if bA == nil { 241 return 0, false 242 } 243 244 bA.mtx.Lock() 245 trueIndices := bA.getTrueIndices() 246 bA.mtx.Unlock() 247 248 if len(trueIndices) == 0 { // no bits set to true 249 return 0, false 250 } 251 252 return trueIndices[RandIntn(len(trueIndices))], true 253 } 254 255 func (bA *BitArray) getTrueIndices() []int { 256 trueIndices := make([]int, 0, bA.Bits) 257 curBit := 0 258 numElems := len(bA.Elems) 259 // set all true indices 260 for i := 0; i < numElems-1; i++ { 261 elem := bA.Elems[i] 262 if elem == 0 { 263 curBit += 64 264 continue 265 } 266 for j := 0; j < 64; j++ { 267 if (elem & (uint64(1) << uint64(j))) > 0 { 268 trueIndices = append(trueIndices, curBit) 269 } 270 curBit++ 271 } 272 } 273 // handle last element 274 lastElem := bA.Elems[numElems-1] 275 numFinalBits := bA.Bits - curBit 276 for i := 0; i < numFinalBits; i++ { 277 if (lastElem & (uint64(1) << uint64(i))) > 0 { 278 trueIndices = append(trueIndices, curBit) 279 } 280 curBit++ 281 } 282 return trueIndices 283 } 284 285 // String returns a string representation of BitArray: BA{<bit-string>}, 286 // where <bit-string> is a sequence of 'x' (1) and '_' (0). 287 // The <bit-string> includes spaces and newlines to help people. 288 // For a simple sequence of 'x' and '_' characters with no spaces or newlines, 289 // see the MarshalJSON() method. 290 // Example: "BA{_x_}" or "nil-BitArray" for nil. 291 func (bA *BitArray) String() string { 292 return bA.StringIndented("") 293 } 294 295 // StringIndented returns the same thing as String(), but applies the indent 296 // at every 10th bit, and twice at every 50th bit. 297 func (bA *BitArray) StringIndented(indent string) string { 298 if bA == nil { 299 return "nil-BitArray" 300 } 301 bA.mtx.Lock() 302 defer bA.mtx.Unlock() 303 return bA.stringIndented(indent) 304 } 305 306 func (bA *BitArray) stringIndented(indent string) string { 307 lines := []string{} 308 bits := "" 309 for i := 0; i < bA.Bits; i++ { 310 if bA.getIndex(i) { 311 bits += "x" 312 } else { 313 bits += "_" 314 } 315 if i%100 == 99 { 316 lines = append(lines, bits) 317 bits = "" 318 } 319 if i%10 == 9 { 320 bits += indent 321 } 322 if i%50 == 49 { 323 bits += indent 324 } 325 } 326 if len(bits) > 0 { 327 lines = append(lines, bits) 328 } 329 return fmt.Sprintf("BA{%v:%v}", bA.Bits, strings.Join(lines, indent)) 330 } 331 332 // Bytes returns the byte representation of the bits within the bitarray. 333 func (bA *BitArray) Bytes() []byte { 334 bA.mtx.Lock() 335 defer bA.mtx.Unlock() 336 337 numBytes := (bA.Bits + 7) / 8 338 bytes := make([]byte, numBytes) 339 for i := 0; i < len(bA.Elems); i++ { 340 elemBytes := [8]byte{} 341 binary.LittleEndian.PutUint64(elemBytes[:], bA.Elems[i]) 342 copy(bytes[i*8:], elemBytes[:]) 343 } 344 return bytes 345 } 346 347 // Update sets the bA's bits to be that of the other bit array. 348 // The copying begins from the begin of both bit arrays. 349 func (bA *BitArray) Update(o *BitArray) { 350 if bA == nil || o == nil { 351 return 352 } 353 bA.mtx.Lock() 354 o.mtx.Lock() 355 defer func() { 356 bA.mtx.Unlock() 357 o.mtx.Unlock() 358 }() 359 360 copy(bA.Elems, o.Elems) 361 } 362 363 // MarshalJSON implements json.Marshaler interface by marshaling bit array 364 // using a custom format: a string of '-' or 'x' where 'x' denotes the 1 bit. 365 func (bA *BitArray) MarshalJSON() ([]byte, error) { 366 if bA == nil { 367 return []byte("null"), nil 368 } 369 370 bA.mtx.Lock() 371 defer bA.mtx.Unlock() 372 373 bits := `"` 374 for i := 0; i < bA.Bits; i++ { 375 if bA.getIndex(i) { 376 bits += `x` 377 } else { 378 bits += `_` 379 } 380 } 381 bits += `"` 382 return []byte(bits), nil 383 } 384 385 var bitArrayJSONRegexp = regexp.MustCompile(`\A"([_x]*)"\z`) 386 387 // UnmarshalJSON implements json.Unmarshaler interface by unmarshaling a custom 388 // JSON description. 389 func (bA *BitArray) UnmarshalJSON(bz []byte) error { 390 b := string(bz) 391 if b == "null" { 392 // This is required e.g. for encoding/json when decoding 393 // into a pointer with pre-allocated BitArray. 394 bA.Bits = 0 395 bA.Elems = nil 396 return nil 397 } 398 399 // Validate 'b'. 400 match := bitArrayJSONRegexp.FindStringSubmatch(b) 401 if match == nil { 402 return fmt.Errorf("BitArray in JSON should be a string of format %q but got %s", bitArrayJSONRegexp.String(), b) 403 } 404 bits := match[1] 405 406 // Construct new BitArray and copy over. 407 numBits := len(bits) 408 bA2 := NewBitArray(numBits) 409 for i := 0; i < numBits; i++ { 410 if bits[i] == 'x' { 411 bA2.SetIndex(i, true) 412 } 413 } 414 *bA = *bA2 415 return nil 416 }