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  }