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