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.

155 lines
3.1 KiB

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