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.

186 lines
3.6 KiB

10 years ago
10 years ago
  1. package common
  2. import (
  3. "io"
  4. "math"
  5. "math/rand"
  6. "strings"
  7. . "github.com/tendermint/tendermint/binary"
  8. )
  9. // Not goroutine safe
  10. type BitArray []uint64
  11. func NewBitArray(length uint) BitArray {
  12. return BitArray(make([]uint64, (length+63)/64))
  13. }
  14. func ReadBitArray(r io.Reader, n *int64, err *error) BitArray {
  15. lengthTotal := ReadUInt32(r, n, err)
  16. lengthWritten := ReadUInt32(r, n, err)
  17. if *err != nil {
  18. return nil
  19. }
  20. buf := make([]uint64, int(lengthTotal))
  21. for i := uint32(0); i < lengthWritten; i++ {
  22. buf[i] = ReadUInt64(r, n, err)
  23. if err != nil {
  24. return nil
  25. }
  26. }
  27. return BitArray(buf)
  28. }
  29. func (bA BitArray) WriteTo(w io.Writer) (n int64, err error) {
  30. // Count the last element > 0.
  31. lastNonzeroIndex := -1
  32. for i, elem := range bA {
  33. if elem > 0 {
  34. lastNonzeroIndex = i
  35. }
  36. }
  37. WriteUInt32(w, uint32(len(bA)), &n, &err)
  38. WriteUInt32(w, uint32(lastNonzeroIndex+1), &n, &err)
  39. for i, elem := range bA {
  40. if i > lastNonzeroIndex {
  41. break
  42. }
  43. WriteUInt64(w, elem, &n, &err)
  44. }
  45. return
  46. }
  47. func (bA BitArray) GetIndex(i uint) bool {
  48. return bA[i/64]&uint64(1<<(i%64)) > 0
  49. }
  50. func (bA BitArray) SetIndex(i uint, v bool) {
  51. if v {
  52. bA[i/64] |= uint64(1 << (i % 64))
  53. } else {
  54. bA[i/64] &= ^uint64(1 << (i % 64))
  55. }
  56. }
  57. func (bA BitArray) Copy() BitArray {
  58. c := make([]uint64, len(bA))
  59. copy(c, bA)
  60. return BitArray(c)
  61. }
  62. func (bA BitArray) Or(o BitArray) BitArray {
  63. c := bA.Copy()
  64. for i, _ := range c {
  65. c[i] = o[i] | c[i]
  66. }
  67. return c
  68. }
  69. func (bA BitArray) And(o BitArray) BitArray {
  70. c := bA.Copy()
  71. for i, _ := range c {
  72. c[i] = o[i] & c[i]
  73. }
  74. return c
  75. }
  76. func (bA BitArray) Not() BitArray {
  77. c := bA.Copy()
  78. for i, _ := range c {
  79. c[i] = ^c[i]
  80. }
  81. return c
  82. }
  83. func (bA BitArray) Sub(o BitArray) BitArray {
  84. return bA.And(o.Not())
  85. }
  86. // NOTE: returns counts or a longer int slice as necessary.
  87. func (bA BitArray) AddToCounts(counts []int) []int {
  88. for bytei := 0; bytei < len(bA); bytei++ {
  89. for biti := 0; biti < 64; biti++ {
  90. if (bA[bytei] & (1 << uint(biti))) == 0 {
  91. continue
  92. }
  93. index := 64*bytei + biti
  94. if len(counts) <= index {
  95. counts = append(counts, make([]int, (index-len(counts)+1))...)
  96. }
  97. counts[index]++
  98. }
  99. }
  100. return counts
  101. }
  102. func (bA BitArray) PickRandom() (int, bool) {
  103. randStart := rand.Intn(len(bA))
  104. for i := 0; i < len(bA); i++ {
  105. bytei := ((i + randStart) % len(bA))
  106. if bA[bytei] > 0 {
  107. randBitStart := rand.Intn(64)
  108. for j := 0; j < 64; j++ {
  109. biti := ((j + randBitStart) % 64)
  110. //fmt.Printf("%X %v %v %v\n", iHas, j, biti, randBitStart)
  111. if (bA[bytei] & (1 << uint(biti))) > 0 {
  112. return 64*int(bytei) + int(biti), true
  113. }
  114. }
  115. panic("should not happen")
  116. }
  117. }
  118. return 0, false
  119. }
  120. // Pick an index from this BitArray that is 1 && whose count is lowest.
  121. func (bA BitArray) PickRarest(counts []int) (rarest int, ok bool) {
  122. smallestCount := math.MaxInt32
  123. for bytei := 0; bytei < len(bA); bytei++ {
  124. if bA[bytei] > 0 {
  125. for biti := 0; biti < 64; biti++ {
  126. if (bA[bytei] & (1 << uint(biti))) == 0 {
  127. continue
  128. }
  129. index := 64*bytei + biti
  130. if counts[index] < smallestCount {
  131. smallestCount = counts[index]
  132. rarest = index
  133. ok = true
  134. }
  135. }
  136. panic("should not happen")
  137. }
  138. }
  139. return
  140. }
  141. func (bA BitArray) String() string {
  142. return bA.StringWithIndent("")
  143. }
  144. func (bA BitArray) StringWithIndent(indent string) string {
  145. lines := []string{}
  146. bits := ""
  147. for i := 0; i < len(bA)*64; i++ {
  148. if bA.GetIndex(uint(i)) {
  149. bits += "X"
  150. } else {
  151. bits += "_"
  152. }
  153. if i%100 == 99 {
  154. lines = append(lines, bits)
  155. bits = ""
  156. }
  157. if i%10 == 9 {
  158. bits += " "
  159. }
  160. if i%50 == 49 {
  161. bits += " "
  162. }
  163. }
  164. if len(bits) > 0 {
  165. lines = append(lines, bits)
  166. }
  167. return strings.Join(lines, indent)
  168. }