ixa/data_structures/
bit_set.rs1pub struct BitSet {
17 storage: Storage,
19 set_count: u32,
21}
22
23enum Storage {
24 Inline(u64),
26 Heap(Box<[u64]>),
28}
29
30impl BitSet {
31 pub fn new(bit_count: usize) -> Self {
32 let storage = if bit_count <= 64 {
33 Storage::Inline(0)
34 } else {
35 let num_words = bit_count.div_ceil(64);
36 Storage::Heap(vec![0u64; num_words].into_boxed_slice())
37 };
38 Self {
39 storage,
40 set_count: 0,
41 }
42 }
43
44 #[inline(always)]
45 pub fn is_empty(&self) -> bool {
46 self.set_count == 0
47 }
48
49 #[inline(always)]
51 pub fn clone_if_nonempty(&self) -> Option<Self> {
52 if self.is_empty() {
53 None
54 } else {
55 Some(self.clone())
56 }
57 }
58
59 #[inline(always)]
61 pub fn capacity(&self) -> usize {
62 match &self.storage {
63 Storage::Inline(_) => 64,
64 Storage::Heap(words) => words.len() * 64,
65 }
66 }
67
68 #[inline(always)]
70 pub fn get(&self, n: usize) -> bool {
71 match &self.storage {
72 Storage::Inline(word) => (word >> n) & 1 != 0,
73 Storage::Heap(words) => {
74 let word = n >> 6; let bit = n & 63; (words[word] >> bit) & 1 != 0
77 }
78 }
79 }
80
81 #[inline(always)]
83 pub fn set(&mut self, n: usize) {
84 match &mut self.storage {
85 Storage::Inline(word) => {
86 let mask = 1u64 << n;
87 if *word & mask == 0 {
88 *word |= mask;
89 self.set_count += 1;
90 }
91 }
92 Storage::Heap(words) => {
93 let idx = n >> 6;
94 let mask = 1u64 << (n & 63);
95 let prev = words[idx];
96 if prev & mask == 0 {
97 words[idx] = prev | mask;
98 self.set_count += 1;
99 }
100 }
101 }
102 }
103
104 #[inline(always)]
106 pub fn reset(&mut self, n: usize) {
107 match &mut self.storage {
108 Storage::Inline(word) => {
109 let mask = 1u64 << n;
110 if *word & mask != 0 {
111 *word &= !mask;
112 self.set_count -= 1;
113 }
114 }
115 Storage::Heap(words) => {
116 let idx = n >> 6;
117 let mask = 1u64 << (n & 63);
118 let prev = words[idx];
119 if prev & mask != 0 {
120 words[idx] = prev & !mask;
121 self.set_count -= 1;
122 }
123 }
124 }
125 }
126
127 pub fn clear(&mut self) {
129 match &mut self.storage {
130 Storage::Inline(word) => *word = 0,
131 Storage::Heap(words) => {
132 for word in words.iter_mut() {
133 *word = 0;
134 }
135 }
136 }
137 self.set_count = 0;
138 }
139}
140
141impl Clone for BitSet {
146 #[inline]
147 fn clone(&self) -> Self {
148 let storage = match &self.storage {
149 Storage::Inline(word) => Storage::Inline(*word),
151 Storage::Heap(words) => Storage::Heap(words.clone()),
153 };
154 Self {
155 storage,
156 set_count: self.set_count,
157 }
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::BitSet;
164
165 #[test]
166 fn capacity_is_at_least_one_word_and_rounds_up_to_whole_words() {
167 for (bit_count, expected_capacity) in [
168 (0, 64),
169 (1, 64),
170 (64, 64),
171 (65, 128),
172 (128, 128),
173 (129, 192),
174 ] {
175 let bit_set = BitSet::new(bit_count);
176 assert_eq!(bit_set.capacity(), expected_capacity);
177 assert!(bit_set.is_empty());
178 }
179 }
180
181 #[test]
182 fn set_and_get_inline_bits() {
183 let mut bit_set = BitSet::new(64);
184
185 for bit in [0, 1, 31, 32, 63] {
186 assert!(!bit_set.get(bit));
187 bit_set.set(bit);
188 assert!(bit_set.get(bit));
189 }
190
191 assert!(!bit_set.is_empty());
192 assert!(!bit_set.get(2));
193 assert!(!bit_set.get(62));
194 }
195
196 #[test]
197 fn set_and_get_heap_bits_across_word_boundaries() {
198 let mut bit_set = BitSet::new(130);
199
200 for bit in [0, 63, 64, 65, 127, 128, 129, 191] {
201 assert!(!bit_set.get(bit));
202 bit_set.set(bit);
203 assert!(bit_set.get(bit));
204 }
205
206 assert!(!bit_set.is_empty());
207 assert!(!bit_set.get(1));
208 assert!(!bit_set.get(66));
209 assert!(!bit_set.get(190));
210 }
211
212 #[test]
213 fn repeated_set_and_reset_are_idempotent() {
214 let mut bit_set = BitSet::new(65);
215
216 bit_set.set(64);
217 bit_set.set(64);
218 bit_set.set(127);
219 bit_set.reset(64);
220 bit_set.reset(64);
221
222 assert!(!bit_set.get(64));
223 assert!(bit_set.get(127));
224 assert!(!bit_set.is_empty());
225
226 bit_set.reset(127);
227 assert!(bit_set.is_empty());
228
229 bit_set.reset(127);
230 assert!(bit_set.is_empty());
231 }
232
233 #[test]
234 fn clear_resets_inline_storage_and_allows_reuse() {
235 let mut bit_set = BitSet::new(64);
236 for bit in [0, 32, 63] {
237 bit_set.set(bit);
238 }
239
240 bit_set.clear();
241
242 assert!(bit_set.is_empty());
243 for bit in [0, 32, 63] {
244 assert!(!bit_set.get(bit));
245 }
246
247 bit_set.set(32);
248 assert!(bit_set.get(32));
249 assert!(!bit_set.is_empty());
250 }
251
252 #[test]
253 fn clear_resets_every_heap_word_and_allows_reuse() {
254 let mut bit_set = BitSet::new(192);
255 for bit in [0, 63, 64, 127, 128, 191] {
256 bit_set.set(bit);
257 }
258
259 bit_set.clear();
260
261 assert!(bit_set.is_empty());
262 for bit in [0, 63, 64, 127, 128, 191] {
263 assert!(!bit_set.get(bit));
264 }
265
266 bit_set.set(128);
267 assert!(bit_set.get(128));
268 assert!(!bit_set.is_empty());
269 }
270
271 #[test]
272 fn inline_clone_is_independent() {
273 assert_clone_is_independent(64, 1, 63);
274 }
275
276 #[test]
277 fn heap_clone_is_independent() {
278 assert_clone_is_independent(128, 64, 127);
279 }
280
281 #[test]
282 fn clone_if_nonempty_returns_none_for_empty_inline_and_heap_storage() {
283 assert!(BitSet::new(64).clone_if_nonempty().is_none());
284 assert!(BitSet::new(65).clone_if_nonempty().is_none());
285 }
286
287 #[test]
288 fn clone_if_nonempty_returns_an_independent_clone() {
289 let mut original = BitSet::new(65);
290 original.set(64);
291
292 let mut cloned = original.clone_if_nonempty().unwrap();
293 cloned.reset(64);
294 cloned.set(65);
295
296 assert!(original.get(64));
297 assert!(!original.get(65));
298 assert!(!cloned.get(64));
299 assert!(cloned.get(65));
300 }
301
302 fn assert_clone_is_independent(bit_count: usize, original_bit: usize, clone_bit: usize) {
303 let mut original = BitSet::new(bit_count);
304 original.set(original_bit);
305
306 let mut cloned = original.clone();
307 cloned.reset(original_bit);
308 cloned.set(clone_bit);
309
310 assert!(original.get(original_bit));
311 assert!(!original.get(clone_bit));
312 assert!(!cloned.get(original_bit));
313 assert!(cloned.get(clone_bit));
314 assert!(!original.is_empty());
315 assert!(!cloned.is_empty());
316 }
317}