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.

250 lines
4.7 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
  1. package common
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "strings"
  6. "sync"
  7. )
  8. type BitArray struct {
  9. mtx sync.Mutex
  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{
  15. Bits: bits,
  16. Elems: make([]uint64, (bits+63)/64),
  17. }
  18. }
  19. func (bA BitArray) Size() uint {
  20. return bA.Bits
  21. }
  22. func (bA BitArray) IsZero() bool {
  23. return bA.Bits == 0
  24. }
  25. // NOTE: behavior is undefined if i >= bA.Bits
  26. func (bA BitArray) GetIndex(i uint) bool {
  27. bA.mtx.Lock()
  28. defer bA.mtx.Unlock()
  29. return bA.getIndex(i)
  30. }
  31. func (bA BitArray) getIndex(i uint) bool {
  32. if i >= bA.Bits {
  33. return false
  34. }
  35. return bA.Elems[i/64]&(uint64(1)<<(i%64)) > 0
  36. }
  37. // NOTE: behavior is undefined if i >= bA.Bits
  38. func (bA BitArray) SetIndex(i uint, v bool) bool {
  39. bA.mtx.Lock()
  40. defer bA.mtx.Unlock()
  41. return bA.setIndex(i, v)
  42. }
  43. func (bA BitArray) setIndex(i uint, v bool) bool {
  44. if i >= bA.Bits {
  45. return false
  46. }
  47. if v {
  48. bA.Elems[i/64] |= (uint64(1) << (i % 64))
  49. } else {
  50. bA.Elems[i/64] &= ^(uint64(1) << (i % 64))
  51. }
  52. return true
  53. }
  54. func (bA BitArray) Copy() BitArray {
  55. bA.mtx.Lock()
  56. defer bA.mtx.Unlock()
  57. return bA.copy()
  58. }
  59. func (bA BitArray) copy() BitArray {
  60. c := make([]uint64, len(bA.Elems))
  61. copy(c, bA.Elems)
  62. return BitArray{
  63. Bits: bA.Bits,
  64. Elems: c,
  65. }
  66. }
  67. func (bA BitArray) copyBits(bits uint) BitArray {
  68. c := make([]uint64, (bits+63)/64)
  69. copy(c, bA.Elems)
  70. return BitArray{
  71. Bits: bits,
  72. Elems: c,
  73. }
  74. }
  75. // Returns a BitArray of larger bits size.
  76. func (bA BitArray) Or(o BitArray) BitArray {
  77. bA.mtx.Lock()
  78. defer bA.mtx.Unlock()
  79. c := bA.copyBits(MaxUint(bA.Bits, o.Bits))
  80. for i := 0; i < len(c.Elems); i++ {
  81. c.Elems[i] |= o.Elems[i]
  82. }
  83. return c
  84. }
  85. // Returns a BitArray of smaller bit size.
  86. func (bA BitArray) And(o BitArray) BitArray {
  87. bA.mtx.Lock()
  88. defer bA.mtx.Unlock()
  89. return bA.and(o)
  90. }
  91. func (bA BitArray) and(o BitArray) BitArray {
  92. c := bA.copyBits(MinUint(bA.Bits, o.Bits))
  93. for i := 0; i < len(c.Elems); i++ {
  94. c.Elems[i] &= o.Elems[i]
  95. }
  96. return c
  97. }
  98. func (bA BitArray) Not() BitArray {
  99. bA.mtx.Lock()
  100. defer bA.mtx.Unlock()
  101. c := bA.copy()
  102. for i := 0; i < len(c.Elems); i++ {
  103. c.Elems[i] = ^c.Elems[i]
  104. }
  105. return c
  106. }
  107. func (bA BitArray) Sub(o BitArray) BitArray {
  108. bA.mtx.Lock()
  109. defer bA.mtx.Unlock()
  110. if bA.Bits > o.Bits {
  111. c := bA.copy()
  112. for i := 0; i < len(o.Elems)-1; i++ {
  113. c.Elems[i] &= ^c.Elems[i]
  114. }
  115. i := uint(len(o.Elems) - 1)
  116. if i >= 0 {
  117. for idx := i * 64; idx < o.Bits; idx++ {
  118. c.setIndex(idx, c.getIndex(idx) && !o.GetIndex(idx))
  119. }
  120. }
  121. return c
  122. } else {
  123. return bA.and(o.Not())
  124. }
  125. }
  126. func (bA BitArray) IsFull() bool {
  127. bA.mtx.Lock()
  128. defer bA.mtx.Unlock()
  129. if bA.Bits == 0 {
  130. return false
  131. }
  132. // Check all elements except the last
  133. for _, elem := range bA.Elems[:len(bA.Elems)-1] {
  134. if (^elem) != 0 {
  135. return false
  136. }
  137. }
  138. // Check that the last element has (lastElemBits) 1's
  139. lastElemBits := (bA.Bits+63)%64 + 1
  140. lastElem := bA.Elems[len(bA.Elems)-1]
  141. return (lastElem+1)&((uint64(1)<<lastElemBits)-1) == 0
  142. }
  143. func (bA BitArray) PickRandom() (uint, bool) {
  144. bA.mtx.Lock()
  145. defer bA.mtx.Unlock()
  146. length := len(bA.Elems)
  147. if length == 0 {
  148. return 0, false
  149. }
  150. randElemStart := rand.Intn(length)
  151. for i := 0; i < length; i++ {
  152. elemIdx := ((i + randElemStart) % length)
  153. if elemIdx < length-1 {
  154. if bA.Elems[elemIdx] > 0 {
  155. randBitStart := rand.Intn(64)
  156. for j := 0; j < 64; j++ {
  157. bitIdx := ((j + randBitStart) % 64)
  158. if (bA.Elems[elemIdx] & (uint64(1) << uint(bitIdx))) > 0 {
  159. return 64*uint(elemIdx) + uint(bitIdx), true
  160. }
  161. }
  162. panic("should not happen")
  163. }
  164. } else {
  165. // Special case for last elem, to ignore straggler bits
  166. elemBits := int(bA.Bits) % 64
  167. if elemBits == 0 {
  168. elemBits = 64
  169. }
  170. randBitStart := rand.Intn(elemBits)
  171. for j := 0; j < elemBits; j++ {
  172. bitIdx := ((j + randBitStart) % elemBits)
  173. if (bA.Elems[elemIdx] & (uint64(1) << uint(bitIdx))) > 0 {
  174. return 64*uint(elemIdx) + uint(bitIdx), true
  175. }
  176. }
  177. }
  178. }
  179. return 0, false
  180. }
  181. func (bA BitArray) String() string {
  182. bA.mtx.Lock()
  183. defer bA.mtx.Unlock()
  184. return bA.stringIndented("")
  185. }
  186. func (bA BitArray) StringIndented(indent string) string {
  187. bA.mtx.Lock()
  188. defer bA.mtx.Unlock()
  189. return bA.StringIndented(indent)
  190. }
  191. func (bA BitArray) stringIndented(indent string) string {
  192. lines := []string{}
  193. bits := ""
  194. for i := uint(0); i < bA.Bits; i++ {
  195. if bA.getIndex(i) {
  196. bits += "X"
  197. } else {
  198. bits += "_"
  199. }
  200. if i%100 == 99 {
  201. lines = append(lines, bits)
  202. bits = ""
  203. }
  204. if i%10 == 9 {
  205. bits += " "
  206. }
  207. if i%50 == 49 {
  208. bits += " "
  209. }
  210. }
  211. if len(bits) > 0 {
  212. lines = append(lines, bits)
  213. }
  214. return fmt.Sprintf("BA{%v:%v}", bA.Bits, strings.Join(lines, indent))
  215. }