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}