github.com/scottcagno/storage@v1.8.0/pkg/bits/bitset.go (about) 1 package bits 2 3 import ( 4 "fmt" 5 "strconv" 6 ) 7 8 const ( 9 ws uint = 64 // try tp match arch, if 32bit, change to 32 10 lg2ws uint = 6 // this should be the log2(ws), so 6 for 64, and 5 for 32 11 all uint = 0xffffffffffffffff // aka, (1<<64)-1, 1 left shift 64-1 12 max = ^uint(0) 13 ) 14 15 // random note: lgws can also be found using bitwise operations (x >> 1) 16 17 // BitSet is a bit set data type 18 type BitSet struct { 19 length uint 20 bits []uint 21 } 22 23 // AlignedSize is an exported version of alignedSize 24 func AlignedSize(size uint) uint { 25 return alignedSize(size) 26 } 27 28 // alignedSize aligns a given size so it works well 29 func alignedSize(size uint) uint { 30 if size > (max - ws + 1) { 31 return max >> lg2ws 32 } 33 return (size + (ws - 1)) >> lg2ws 34 } 35 36 // resize adds additional words to incorporate new bits if needed 37 func (b *BitSet) resize(i uint) { 38 if i < b.length || i > max { 39 return 40 } 41 nsize := int(alignedSize(i + 1)) 42 if b.bits == nil { 43 b.bits = make([]uint, nsize) 44 } else if cap(b.bits) >= nsize { 45 b.bits = b.bits[:nsize] // fast resize 46 } else if len(b.bits) < nsize { 47 newset := make([]uint, nsize, 2*nsize) // increase capacity 2x 48 copy(newset, b.bits) 49 b.bits = newset 50 } 51 b.length = i + 1 52 } 53 54 // NewBitSet sets up and retruns a new BitSet structure 55 func NewBitSet(length uint) *BitSet { 56 alignedLen := alignedSize(length) 57 return &BitSet{ 58 length: length, 59 bits: make([]uint, alignedLen), 60 } 61 } 62 63 // SetMany is identical to calling Set repeatedly 64 func (b *BitSet) SetMany(ii ...uint) *BitSet { 65 for _, i := range ii { 66 b.Set(i) 67 } 68 return b 69 } 70 71 // Set sets bit i to 1. The capacity of the bitset grows accordingly 72 func (b *BitSet) Set(i uint) *BitSet { 73 b.resize(i) // resize if need be 74 //if i >= b.length { 75 // return b 76 //} 77 b.bits[i>>lg2ws] |= 1 << (i & (ws - 1)) 78 return b 79 } 80 81 // Unset clears bit i, aka sets it to 0 82 func (b *BitSet) Unset(i uint) *BitSet { 83 if i >= b.length { 84 return b 85 } 86 b.bits[i>>lg2ws] &^= 1 << (i & (ws - 1)) 87 return b 88 } 89 90 // IsSet tests and returns a boolean if bit i is set 91 func (b *BitSet) IsSet(i uint) bool { 92 if i >= b.length { 93 return false 94 } 95 return b.bits[i>>lg2ws]&(1<<(i&(ws-1))) != 0 96 } 97 98 // Value returns the value 99 func (b *BitSet) Value(i uint) uint { 100 if i >= b.length { 101 return 0 102 } 103 return b.bits[i>>lg2ws] & (1 << (i & (ws - 1))) 104 } 105 106 // Len returns the number of bits in the bitset 107 func (b *BitSet) Len() uint { 108 return b.length 109 } 110 111 // print binary value of bitset 112 func (b *BitSet) String() string { 113 //var res string = "16" // set this to the "bit resolution" you'd like to see 114 var res = strconv.Itoa(int(b.length)) 115 return fmt.Sprintf("%."+res+"b (%s bits)", b.bits, res) 116 } 117 118 func (b *BitSet) PercentageFull() (int, float64) { 119 var isset int 120 for i := uint(0); i < b.length; i++ { 121 if b.bits[i>>lg2ws]&(1<<(i&(ws-1))) != 0 { 122 isset++ 123 } 124 } 125 return isset, float64(isset) / float64(b.length) 126 }