github.com/Finschia/ostracon@v1.1.5/libs/bits/bit_array.go (about)

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