Search Apps Documentation Source Content File Folder Download Copy Actions Download

bitset.gno

4.08 Kb · 193 lines
  1package bitset
  2
  3import "strings"
  4
  5const bitsPerWord = 64
  6
  7// BitSet implements an arbitrary-size bit array.
  8type BitSet struct {
  9	words []uint64
 10}
 11
 12// New creates a new BitSet pre-allocated to hold at least size bits.
 13func New(size uint64) BitSet {
 14	if size == 0 {
 15		return BitSet{}
 16	}
 17	return BitSet{words: make([]uint64, wordIndex(size-1)+1)}
 18}
 19
 20// Set turns on the bit at a given position.
 21func (b *BitSet) Set(i uint64) {
 22	idx := wordIndex(i)
 23	if idx >= len(b.words) {
 24		b.grow(idx + 1)
 25	}
 26	b.words[idx] |= bitMask(i) // Turn bit on
 27}
 28
 29// Clear turns off the bit at a given position.
 30func (b *BitSet) Clear(i uint64) {
 31	idx := wordIndex(i)
 32	if idx < len(b.words) {
 33		b.words[idx] &^= bitMask(i) // Turn bit off
 34	}
 35}
 36
 37// ClearAll turns off all bits.
 38// The size of the bitset remains unchanged.
 39func (b *BitSet) ClearAll() {
 40	for i := range b.words {
 41		b.words[i] = 0
 42	}
 43}
 44
 45// Compact reclaims memory by removing trailing zero words.
 46func (b *BitSet) Compact() {
 47	end := len(b.words)
 48	for ; end > 0 && b.words[end-1] == 0; end-- {
 49	}
 50	words := make([]uint64, end)
 51	copy(words, b.words)
 52	b.words = words
 53}
 54
 55// IsSet checks whether the bit at a given position is set.
 56func (b BitSet) IsSet(i uint64) bool {
 57	idx := wordIndex(i)
 58	if idx >= len(b.words) {
 59		return false // Bit has not been set yet
 60	}
 61	return b.words[idx]&bitMask(i) != 0
 62}
 63
 64// Size returns the total number of bits (including unset) currently stored.
 65// It's the total space allocated within the set in bits.
 66func (b BitSet) Size() int {
 67	return len(b.words) * bitsPerWord
 68}
 69
 70// Len returns the number of set bits.
 71func (b BitSet) Len() int {
 72	var count int
 73	for _, w := range b.words {
 74		count += countSetBits(w)
 75	}
 76	return count
 77}
 78
 79// And performs an in-place AND with other bitset.
 80// Bits beyond the other bitset are cleared.
 81func (b *BitSet) And(other BitSet) {
 82	for i := range b.words {
 83		if i < len(other.words) {
 84			b.words[i] &= other.words[i]
 85		} else {
 86			b.words[i] = 0
 87		}
 88	}
 89}
 90
 91// Or performs an in-place OR (union) with other bitset.
 92// Current bitset grows if the other bitset is bigger.
 93func (b *BitSet) Or(other BitSet) {
 94	otherLen := len(other.words)
 95	if otherLen > len(b.words) {
 96		b.grow(otherLen)
 97	}
 98
 99	for i := range other.words {
100		b.words[i] |= other.words[i]
101	}
102}
103
104// Xor performs an in-place XOR with other.
105// Current bitset grows if the other bitset is bigger.
106func (b *BitSet) Xor(other BitSet) {
107	otherLen := len(other.words)
108	if otherLen > len(b.words) {
109		b.grow(otherLen)
110	}
111
112	for i := range other.words {
113		b.words[i] ^= other.words[i]
114	}
115}
116
117// Equal checks whether other bitset have exactly the same bits set.
118func (b BitSet) Equal(other BitSet) bool {
119	short, long := b.words, other.words
120	if len(short) > len(long) {
121		short, long = long, short
122	}
123
124	for i := range short {
125		if short[i] != long[i] {
126			return false
127		}
128	}
129
130	// Any trailing words in the longer set must be zero
131	for i := len(short); i < len(long); i++ {
132		if long[i] != 0 {
133			return false
134		}
135	}
136	return true
137}
138
139// PaddedString returns a binary representation of the bitset with zero padding.
140// Representation uses MSB-first binary representation.
141func (b BitSet) PaddedString() string {
142	wordCount := len(b.words)
143	if wordCount == 0 {
144		return ""
145	}
146
147	buf := make([]byte, wordCount*bitsPerWord)
148	for i, w := range b.words {
149		base := (wordCount - 1 - i) * bitsPerWord
150		for j := 0; j < bitsPerWord; j++ {
151			if w>>uint64(bitsPerWord-1-j)&1 == 1 {
152				buf[base+j] = '1'
153			} else {
154				buf[base+j] = '0'
155			}
156		}
157	}
158	return string(buf)
159}
160
161// String returns a binary representation of the bitset.
162// Representation uses MSB-first binary representation.
163func (b BitSet) String() string {
164	s := strings.TrimLeft(b.PaddedString(), "0")
165	if s == "" && len(b.words) > 0 {
166		return "0"
167	}
168	return s
169}
170
171func (b *BitSet) grow(length int) {
172	words := make([]uint64, length)
173	copy(words, b.words)
174	b.words = words
175}
176
177func wordIndex(i uint64) int {
178	return int(i / bitsPerWord)
179}
180
181func bitMask(i uint64) uint64 {
182	return 1 << (i % bitsPerWord)
183}
184
185func countSetBits(x uint64) int {
186	// Count the number of set bits using Kernighan's algorithm
187	var count int
188	for x != 0 {
189		x &= x - 1
190		count++
191	}
192	return count
193}