You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
3.5 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package binary
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "strings"
  6. . "github.com/tendermint/tendermint/common"
  7. )
  8. // Not goroutine safe
  9. type BitArray struct {
  10. Bits uint // NOTE: persisted via reflect, must be exported
  11. Elems []uint64 // NOTE: persisted via reflect, must be exported
  12. }
  13. func NewBitArray(bits uint) BitArray {
  14. return BitArray{bits, make([]uint64, (bits+63)/64)}
  15. }
  16. func (bA BitArray) Size() uint {
  17. return bA.Bits
  18. }
  19. func (bA BitArray) IsZero() bool {
  20. return bA.Bits == 0
  21. }
  22. // NOTE: behavior is undefined if i >= bA.Bits
  23. func (bA BitArray) GetIndex(i uint) bool {
  24. if i >= bA.Bits {
  25. return false
  26. }
  27. return bA.Elems[i/64]&uint64(1<<(i%64)) > 0
  28. }
  29. // NOTE: behavior is undefined if i >= bA.Bits
  30. func (bA BitArray) SetIndex(i uint, v bool) bool {
  31. if i >= bA.Bits {
  32. return false
  33. }
  34. if v {
  35. bA.Elems[i/64] |= uint64(1 << (i % 64))
  36. } else {
  37. bA.Elems[i/64] &= ^uint64(1 << (i % 64))
  38. }
  39. return true
  40. }
  41. func (bA BitArray) Copy() BitArray {
  42. c := make([]uint64, len(bA.Elems))
  43. copy(c, bA.Elems)
  44. return BitArray{bA.Bits, c}
  45. }
  46. func (bA BitArray) copyBits(bits uint) BitArray {
  47. c := make([]uint64, (bits+63)/64)
  48. copy(c, bA.Elems)
  49. return BitArray{bits, c}
  50. }
  51. // Returns a BitArray of larger bits size.
  52. func (bA BitArray) Or(o BitArray) BitArray {
  53. c := bA.copyBits(MaxUint(bA.Bits, o.Bits))
  54. for i := 0; i < len(c.Elems); i++ {
  55. c.Elems[i] |= o.Elems[i]
  56. }
  57. return c
  58. }
  59. // Returns a BitArray of smaller bit size.
  60. func (bA BitArray) And(o BitArray) BitArray {
  61. c := bA.copyBits(MinUint(bA.Bits, o.Bits))
  62. for i := 0; i < len(c.Elems); i++ {
  63. c.Elems[i] &= o.Elems[i]
  64. }
  65. return c
  66. }
  67. func (bA BitArray) Not() BitArray {
  68. c := bA.Copy()
  69. for i := 0; i < len(c.Elems); i++ {
  70. c.Elems[i] = ^c.Elems[i]
  71. }
  72. return c
  73. }
  74. func (bA BitArray) Sub(o BitArray) BitArray {
  75. if bA.Bits > o.Bits {
  76. c := bA.Copy()
  77. for i := 0; i < len(o.Elems)-1; i++ {
  78. c.Elems[i] &= ^c.Elems[i]
  79. }
  80. i := uint(len(o.Elems) - 1)
  81. if i >= 0 {
  82. for idx := i * 64; idx < o.Bits; idx++ {
  83. c.SetIndex(idx, c.GetIndex(idx) && !o.GetIndex(idx))
  84. }
  85. }
  86. return c
  87. } else {
  88. return bA.And(o.Not())
  89. }
  90. }
  91. func (bA BitArray) PickRandom() (uint, bool) {
  92. length := len(bA.Elems)
  93. if length == 0 {
  94. return 0, false
  95. }
  96. randElemStart := rand.Intn(length)
  97. for i := 0; i < length; i++ {
  98. elemIdx := ((i + randElemStart) % length)
  99. if elemIdx < length-1 {
  100. if bA.Elems[elemIdx] > 0 {
  101. randBitStart := rand.Intn(64)
  102. for j := 0; j < 64; j++ {
  103. bitIdx := ((j + randBitStart) % 64)
  104. if (bA.Elems[elemIdx] & (1 << uint(bitIdx))) > 0 {
  105. return 64*uint(elemIdx) + uint(bitIdx), true
  106. }
  107. }
  108. panic("should not happen")
  109. }
  110. } else {
  111. // Special case for last elem, to ignore straggler bits
  112. elemBits := int(bA.Bits) % 64
  113. if elemBits == 0 {
  114. elemBits = 64
  115. }
  116. randBitStart := rand.Intn(elemBits)
  117. for j := 0; j < elemBits; j++ {
  118. bitIdx := ((j + randBitStart) % elemBits)
  119. if (bA.Elems[elemIdx] & (1 << uint(bitIdx))) > 0 {
  120. return 64*uint(elemIdx) + uint(bitIdx), true
  121. }
  122. }
  123. }
  124. }
  125. return 0, false
  126. }
  127. func (bA BitArray) String() string {
  128. return bA.StringIndented("")
  129. }
  130. func (bA BitArray) StringIndented(indent string) string {
  131. lines := []string{}
  132. bits := ""
  133. for i := uint(0); i < bA.Bits; i++ {
  134. if bA.GetIndex(i) {
  135. bits += "X"
  136. } else {
  137. bits += "_"
  138. }
  139. if i%100 == 99 {
  140. lines = append(lines, bits)
  141. bits = ""
  142. }
  143. if i%10 == 9 {
  144. bits += " "
  145. }
  146. if i%50 == 49 {
  147. bits += " "
  148. }
  149. }
  150. if len(bits) > 0 {
  151. lines = append(lines, bits)
  152. }
  153. return fmt.Sprintf("BA{%v:%v}", bA.Bits, strings.Join(lines, indent))
  154. }