mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-23 01:41:31 +00:00
fixed algorithm
This commit is contained in:
155
common/bit_array.go
Normal file
155
common/bit_array.go
Normal file
@ -0,0 +1,155 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
|
||||
. "github.com/tendermint/tendermint/binary"
|
||||
)
|
||||
|
||||
// Not goroutine safe
|
||||
type BitArray []uint64
|
||||
|
||||
func NewBitArray(length uint) BitArray {
|
||||
return BitArray(make([]uint64, (length+63)/64))
|
||||
}
|
||||
|
||||
func ReadBitArray(r io.Reader, n *int64, err *error) BitArray {
|
||||
lengthTotal := ReadUInt32(r, n, err)
|
||||
lengthWritten := ReadUInt32(r, n, err)
|
||||
if *err != nil {
|
||||
return nil
|
||||
}
|
||||
buf := make([]uint64, int(lengthTotal))
|
||||
for i := uint32(0); i < lengthWritten; i++ {
|
||||
buf[i] = ReadUInt64(r, n, err)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return BitArray(buf)
|
||||
}
|
||||
|
||||
func (bA BitArray) WriteTo(w io.Writer) (n int64, err error) {
|
||||
// Count the last element > 0.
|
||||
lastNonzeroIndex := -1
|
||||
for i, elem := range bA {
|
||||
if elem > 0 {
|
||||
lastNonzeroIndex = i
|
||||
}
|
||||
}
|
||||
WriteUInt32(w, uint32(len(bA)), &n, &err)
|
||||
WriteUInt32(w, uint32(lastNonzeroIndex+1), &n, &err)
|
||||
for i, elem := range bA {
|
||||
if i > lastNonzeroIndex {
|
||||
break
|
||||
}
|
||||
WriteUInt64(w, elem, &n, &err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (bA BitArray) GetIndex(i uint) bool {
|
||||
return bA[i/64]&uint64(1<<(i%64)) > 0
|
||||
}
|
||||
|
||||
func (bA BitArray) SetIndex(i uint, v bool) {
|
||||
if v {
|
||||
bA[i/64] |= uint64(1 << (i % 64))
|
||||
} else {
|
||||
bA[i/64] &= ^uint64(1 << (i % 64))
|
||||
}
|
||||
}
|
||||
|
||||
func (bA BitArray) Copy() BitArray {
|
||||
c := make([]uint64, len(bA))
|
||||
copy(c, bA)
|
||||
return BitArray(c)
|
||||
}
|
||||
|
||||
func (bA BitArray) Or(o BitArray) BitArray {
|
||||
c := bA.Copy()
|
||||
for i, _ := range c {
|
||||
c[i] = o[i] | c[i]
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (bA BitArray) And(o BitArray) BitArray {
|
||||
c := bA.Copy()
|
||||
for i, _ := range c {
|
||||
c[i] = o[i] & c[i]
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (bA BitArray) Not() BitArray {
|
||||
c := bA.Copy()
|
||||
for i, _ := range c {
|
||||
c[i] = ^c[i]
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (bA BitArray) Sub(o BitArray) BitArray {
|
||||
return bA.And(o.Not())
|
||||
}
|
||||
|
||||
// NOTE: returns counts or a longer int slice as necessary.
|
||||
func (bA BitArray) AddToCounts(counts []int) []int {
|
||||
for bytei := 0; bytei < len(bA); bytei++ {
|
||||
for biti := 0; biti < 64; biti++ {
|
||||
if (bA[bytei] & (1 << uint(biti))) == 0 {
|
||||
continue
|
||||
}
|
||||
index := 64*bytei + biti
|
||||
if len(counts) <= index {
|
||||
counts = append(counts, make([]int, (index-len(counts)+1))...)
|
||||
}
|
||||
counts[index]++
|
||||
}
|
||||
}
|
||||
return counts
|
||||
}
|
||||
|
||||
func (bA BitArray) PickRandom() (int, bool) {
|
||||
randStart := rand.Intn(len(bA))
|
||||
for i := 0; i < len(bA); i++ {
|
||||
bytei := ((i + randStart) % len(bA))
|
||||
if bA[bytei] > 0 {
|
||||
randBitStart := rand.Intn(64)
|
||||
for j := 0; j < 64; j++ {
|
||||
biti := ((j + randBitStart) % 64)
|
||||
//fmt.Printf("%X %v %v %v\n", iHas, j, biti, randBitStart)
|
||||
if (bA[bytei] & (1 << uint(biti))) > 0 {
|
||||
return 64*int(bytei) + int(biti), true
|
||||
}
|
||||
}
|
||||
panic("should not happen")
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Pick an index from this BitArray that is 1 && whose count is lowest.
|
||||
func (bA BitArray) PickRarest(counts []int) (rarest int, ok bool) {
|
||||
smallestCount := math.MaxInt32
|
||||
for bytei := 0; bytei < len(bA); bytei++ {
|
||||
if bA[bytei] > 0 {
|
||||
for biti := 0; biti < 64; biti++ {
|
||||
if (bA[bytei] & (1 << uint(biti))) == 0 {
|
||||
continue
|
||||
}
|
||||
index := 64*bytei + biti
|
||||
if counts[index] < smallestCount {
|
||||
smallestCount = counts[index]
|
||||
rarest = index
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
panic("should not happen")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
Reference in New Issue
Block a user