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  }