bitset_fixed_utils/lib.rs
1//! A bunch of utility stuffs that I use when working with bitsets in Rust
2
3use std::{iter::Cloned, slice::Iter, cmp::Ordering};
4
5use bitset_fixed::BitSet;
6
7/// This structure defines an iterator capable of iterating over the 1-bits of
8/// a fixed bitset. It uses word representation of the items in the set, so it
9/// should be more efficient to use than a crude iteration over the elements of
10/// the set.
11///
12/// # Example
13/// ```
14/// # use bitset_fixed::BitSet;
15/// # use ddo::BitSetIter;
16///
17/// let mut bit_set = BitSet::new(5);
18/// bit_set.set(1, true);
19/// bit_set.set(2, true);
20/// bit_set.set(4, true);
21///
22/// // Successively prints 1, 2, 4
23/// for x in BitSetIter::new(&bit_set) {
24/// println!("{}", x);
25/// }
26/// ```
27///
28pub struct BitSetIter<'a> {
29 /// An iterator over the buffer of words of the bitset
30 iter: Cloned<Iter<'a, u64>>,
31 /// The current word (or none if we exhausted all iterations)
32 word: Option<u64>,
33 /// The value of position 0 in the current word
34 base: usize,
35 /// An offset in the current word
36 offset: usize,
37}
38impl BitSetIter<'_> {
39 /// This method creates an iterator for the given bitset from an immutable
40 /// reference to that bitset.
41 pub fn new(bs: &BitSet) -> BitSetIter {
42 let mut iter = bs.buffer().iter().cloned();
43 let word = iter.next();
44 BitSetIter {iter, word, base: 0, offset: 0}
45 }
46}
47/// `BitSetIter` is an iterator over the one bits of the bitset. As such, it
48/// implements the standard `Iterator` trait.
49impl Iterator for BitSetIter<'_> {
50 type Item = usize;
51
52 /// Returns the nex element from the iteration, or None, if there are no more
53 /// elements to iterate upon.
54 fn next(&mut self) -> Option<Self::Item> {
55 while let Some(w) = self.word {
56 if w == 0 || self.offset >= 64 {
57 self.word = self.iter.next();
58 self.base += 64;
59 self.offset = 0;
60 } else {
61 let mut mask = 1_u64 << self.offset as u64;
62 while (w & mask) == 0 && self.offset < 64 {
63 mask <<= 1;
64 self.offset += 1;
65 }
66 if self.offset < 64 {
67 let ret = Some(self.base + self.offset);
68 self.offset += 1;
69 return ret;
70 }
71 }
72 }
73 None
74 }
75}
76
77/// A totally ordered Bitset wrapper. Useful to implement tie break mechanisms.
78/// This wrapper orders the bitsets according to the lexical order of their
79/// underlying bits.
80///
81/// # Note:
82/// This implementation uses the underlying _words_ representation of the
83/// bitsets to perform several comparisons at once. Hence, using a `LexBitSet`
84/// should be more efficient than trying to establish the total ordering
85/// yourself with a loop on the 1-bits of the two sets.
86///
87/// # Example
88/// ```
89/// # use bitset_fixed::BitSet;
90/// # use ddo::LexBitSet;
91///
92/// let mut a = BitSet::new(5);
93/// let mut b = BitSet::new(5);
94///
95/// a.set(2, true); // bits 0..2 match for a and b
96/// b.set(2, true);
97///
98/// a.set(3, false); // a and b diverge on bit 3
99/// b.set(3, true); // and a has a 0 bit in that pos
100///
101/// a.set(4, true); // anything that remains after
102/// b.set(4, false); // the firs lexicographical difference is ignored
103///
104/// assert!(LexBitSet(&a) < LexBitSet(&b));
105/// ```
106///
107#[derive(Debug)]
108pub struct LexBitSet<'a>(pub &'a BitSet);
109
110/// The `LexBitSet` implements a total order on bitsets. As such, it must
111/// implement the standard trait `Ord`.
112///
113/// # Note:
114/// This implementation uses the underlying _words_ representation of the
115/// bitsets to perform several comparisons at once. Hence, using a `LexBitSet`
116/// should be more efficient than trying to establish the total ordering
117/// yourself with a loop on the 1-bits of the two sets.
118impl Ord for LexBitSet<'_> {
119 fn cmp(&self, other: &Self) -> Ordering {
120 let mut x = self.0.buffer().iter().cloned();
121 let mut y = other.0.buffer().iter().cloned();
122 let end = x.len().max(y.len());
123
124 for _ in 0..end {
125 let xi = x.next().unwrap_or(0);
126 let yi = y.next().unwrap_or(0);
127 if xi != yi {
128 let mut mask = 1_u64;
129 for _ in 0..64 {
130 let bit_x = xi & mask;
131 let bit_y = yi & mask;
132 if bit_x != bit_y {
133 return bit_x.cmp(&bit_y);
134 }
135 mask <<= 1;
136 }
137 }
138 }
139 Ordering::Equal
140 }
141}
142
143/// Because it is a total order, `LexBitSet` must also be a partial order.
144/// Hence, it must implement the standard trait `PartialOrd`.
145impl PartialOrd for LexBitSet<'_> {
146 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
147 Some(self.cmp(other))
148 }
149}
150
151/// Because `LexBitSet` defines a total order, it makes sense to consider that
152/// it also defines an equivalence relation. As such, it implements the standard
153/// `Eq` and `PartialEq` traits.
154impl Eq for LexBitSet<'_> {}
155
156/// Having `LexBitSet` to implement `PartialEq` means that it _at least_ defines
157/// a partial equivalence relation.
158impl PartialEq for LexBitSet<'_> {
159 fn eq(&self, other: &Self) -> bool {
160 self.0 == other.0 || self.cmp(other) == Ordering::Equal
161 }
162}
163
164
165#[cfg(test)]
166/// These tests validate the behavior of the bitset iterator `BitSetIter`.
167mod tests_bitset_iter {
168 use bitset_fixed::BitSet;
169 use crate::BitSetIter;
170
171 #[test]
172 fn bsiter_collect() {
173 let mut bit_set = BitSet::new(5);
174 bit_set.set(1, true);
175 bit_set.set(2, true);
176 bit_set.set(4, true);
177
178 let iter = BitSetIter::new(&bit_set);
179 let items = iter.collect::<Vec<usize>>();
180
181 assert_eq!(items, vec![1, 2, 4]);
182 }
183 #[test]
184 fn bsiter_next_normal_case() {
185 let mut bit_set = BitSet::new(5);
186 bit_set.set(1, true);
187 bit_set.set(2, true);
188 bit_set.set(4, true);
189
190 let mut iter = BitSetIter::new(&bit_set);
191 assert_eq!(Some(1), iter.next());
192 assert_eq!(Some(2), iter.next());
193 assert_eq!(Some(4), iter.next());
194 assert_eq!(None , iter.next());
195 }
196 #[test]
197 fn bsiter_no_items() {
198 let bit_set = BitSet::new(5);
199 let mut iter = BitSetIter::new(&bit_set);
200
201 assert_eq!(None, iter.next());
202 assert_eq!(None, iter.next());
203 assert_eq!(None, iter.next());
204 }
205 #[test]
206 fn bsiter_mutiple_words() {
207 let mut bit_set = BitSet::new(128);
208 bit_set.set( 1, true);
209 bit_set.set( 50, true);
210 bit_set.set( 66, true);
211 bit_set.set(100, true);
212
213 let mut iter = BitSetIter::new(&bit_set);
214 assert_eq!(Some( 1), iter.next());
215 assert_eq!(Some( 50), iter.next());
216 assert_eq!(Some( 66), iter.next());
217 assert_eq!(Some(100), iter.next());
218 assert_eq!(None , iter.next());
219 }
220}
221#[cfg(test)]
222/// These tests validate the behavior of the lexicographically ordered bitsets
223/// `LexBitSet`.
224mod tests_lexbitset {
225 use bitset_fixed::BitSet;
226 use crate::LexBitSet;
227
228 #[test]
229 fn same_size_less_than() {
230 let mut a = BitSet::new(200);
231 let mut b = BitSet::new(200);
232
233 a.set(2, true); // bits 0..2 match for a and b
234 b.set(2, true);
235
236 a.set(3, false); // a and b diverge on bit 3
237 b.set(3, true); // and a has a 0 bit in that pos
238
239 a.set(4, true); // anything that remains after
240 b.set(4, false); // the firs lexicographical difference is ignored
241
242 a.set(150, true);
243 b.set(150, true);
244
245 assert!(LexBitSet(&a) <= LexBitSet(&b));
246 assert!(LexBitSet(&a) < LexBitSet(&b));
247 }
248 #[test]
249 fn same_size_greater_than() {
250 let mut a = BitSet::new(200);
251 let mut b = BitSet::new(200);
252
253 a.set(2, true); // bits 0..2 match for a and b
254 b.set(2, true);
255
256 a.set(3, false); // a and b diverge on bit 3
257 b.set(3, true); // and a has a 0 bit in that pos
258
259 a.set(4, true); // anything that remains after
260 b.set(4, false); // the firs lexicographical difference is ignored
261
262 a.set(150, true);
263 b.set(150, true);
264
265 assert!(LexBitSet(&b) >= LexBitSet(&a));
266 assert!(LexBitSet(&b) > LexBitSet(&a));
267 }
268 #[test]
269 fn same_size_equal() {
270 let mut a = BitSet::new(200);
271 let mut b = BitSet::new(200);
272
273 a.set(2, true); // bits 0..2 match for a and b
274 b.set(2, true);
275
276 a.set(150, true);
277 b.set(150, true);
278
279 assert!(LexBitSet(&a) >= LexBitSet(&b));
280 assert!(LexBitSet(&b) >= LexBitSet(&a));
281
282 assert_eq!(LexBitSet(&a), LexBitSet(&b));
283 assert_eq!(LexBitSet(&a), LexBitSet(&a));
284 assert_eq!(LexBitSet(&b), LexBitSet(&b));
285 }
286
287 #[test]
288 /// For different sized bitsets, it behaves as though they were padded with
289 /// trailing zeroes.
290 fn different_sizes_considered_padded_with_zeroes() {
291 let mut a = BitSet::new(20);
292 let mut b = BitSet::new(200);
293
294 a.set(2, true); // bits 0..2 match for a and b
295 b.set(2, true);
296
297 assert_eq!(LexBitSet(&a), LexBitSet(&b));
298
299 b.set(150, true);
300 assert!(LexBitSet(&a) <= LexBitSet(&b));
301 assert!(LexBitSet(&a) < LexBitSet(&b));
302 }
303}