proptest/
bits.rs

1//-
2// Copyright 2017, 2018 The proptest developers
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! Strategies for working with bit sets.
11//!
12//! Besides `BitSet` itself, this also defines strategies for all the primitive
13//! integer types. These strategies are appropriate for integers which are used
14//! as bit flags, etc; e.g., where the most reasonable simplification of `64`
15//! is `0` (clearing one bit) and not `63` (clearing one bit but setting 6
16//! others). For integers treated as numeric values, see the corresponding
17//! modules of the `num` module instead.
18
19use crate::std_facade::{fmt, Vec};
20use core::marker::PhantomData;
21use core::mem;
22
23#[cfg(feature = "bit-set")]
24use bit_set::BitSet;
25#[cfg(feature = "bit-set")]
26use bit_vec::BitVec;
27use rand::{self, seq::IteratorRandom, Rng};
28
29use crate::collection::SizeRange;
30use crate::num::sample_uniform_incl;
31use crate::strategy::*;
32use crate::test_runner::*;
33
34/// Trait for types which can be handled with `BitSetStrategy`.
35#[cfg_attr(clippy, allow(len_without_is_empty))]
36pub trait BitSetLike: Clone + fmt::Debug {
37    /// Create a new value of `Self` with space for up to `max` bits, all
38    /// initialised to zero.
39    fn new_bitset(max: usize) -> Self;
40    /// Return an upper bound on the greatest bit set _plus one_.
41    fn len(&self) -> usize;
42    /// Test whether the given bit is set.
43    fn test(&self, ix: usize) -> bool;
44    /// Set the given bit.
45    fn set(&mut self, ix: usize);
46    /// Clear the given bit.
47    fn clear(&mut self, ix: usize);
48    /// Return the number of bits set.
49    ///
50    /// This has a default for backwards compatibility, which simply does a
51    /// linear scan through the bits. Implementations are strongly encouraged
52    /// to override this.
53    fn count(&self) -> usize {
54        let mut n = 0;
55        for i in 0..self.len() {
56            if self.test(i) {
57                n += 1;
58            }
59        }
60        n
61    }
62}
63
64macro_rules! int_bitset {
65    ($typ:ty) => {
66        impl BitSetLike for $typ {
67            fn new_bitset(_: usize) -> Self {
68                0
69            }
70            fn len(&self) -> usize {
71                mem::size_of::<$typ>() * 8
72            }
73            fn test(&self, ix: usize) -> bool {
74                0 != (*self & ((1 as $typ) << ix))
75            }
76            fn set(&mut self, ix: usize) {
77                *self |= (1 as $typ) << ix;
78            }
79            fn clear(&mut self, ix: usize) {
80                *self &= !((1 as $typ) << ix);
81            }
82            fn count(&self) -> usize {
83                self.count_ones() as usize
84            }
85        }
86    };
87}
88int_bitset!(u8);
89int_bitset!(u16);
90int_bitset!(u32);
91int_bitset!(u64);
92int_bitset!(usize);
93int_bitset!(i8);
94int_bitset!(i16);
95int_bitset!(i32);
96int_bitset!(i64);
97int_bitset!(isize);
98
99#[cfg(feature = "bit-set")]
100#[cfg_attr(docsrs, doc(cfg(feature = "bit-set")))]
101impl BitSetLike for BitSet {
102    fn new_bitset(max: usize) -> Self {
103        BitSet::with_capacity(max)
104    }
105
106    fn len(&self) -> usize {
107        self.capacity()
108    }
109
110    fn test(&self, bit: usize) -> bool {
111        self.contains(bit)
112    }
113
114    fn set(&mut self, bit: usize) {
115        self.insert(bit);
116    }
117
118    fn clear(&mut self, bit: usize) {
119        self.remove(bit);
120    }
121
122    fn count(&self) -> usize {
123        self.len()
124    }
125}
126
127impl BitSetLike for Vec<bool> {
128    fn new_bitset(max: usize) -> Self {
129        vec![false; max]
130    }
131
132    fn len(&self) -> usize {
133        self.len()
134    }
135
136    fn test(&self, bit: usize) -> bool {
137        if bit >= self.len() {
138            false
139        } else {
140            self[bit]
141        }
142    }
143
144    fn set(&mut self, bit: usize) {
145        if bit >= self.len() {
146            self.resize(bit + 1, false);
147        }
148
149        self[bit] = true;
150    }
151
152    fn clear(&mut self, bit: usize) {
153        if bit < self.len() {
154            self[bit] = false;
155        }
156    }
157
158    fn count(&self) -> usize {
159        self.iter().filter(|&&b| b).count()
160    }
161}
162
163/// Generates values as a set of bits between the two bounds.
164///
165/// Values are generated by uniformly setting individual bits to 0
166/// or 1 between the bounds. Shrinking iteratively clears bits.
167#[must_use = "strategies do nothing unless used"]
168#[derive(Clone, Copy, Debug)]
169pub struct BitSetStrategy<T: BitSetLike> {
170    min: usize,
171    max: usize,
172    mask: Option<T>,
173}
174
175impl<T: BitSetLike> BitSetStrategy<T> {
176    /// Create a strategy which generates values where bits between `min`
177    /// (inclusive) and `max` (exclusive) may be set.
178    ///
179    /// Due to the generics, the functions in the typed submodules are usually
180    /// preferable to calling this directly.
181    pub fn new(min: usize, max: usize) -> Self {
182        BitSetStrategy {
183            min,
184            max,
185            mask: None,
186        }
187    }
188
189    /// Create a strategy which generates values where any bits set (and only
190    /// those bits) in `mask` may be set.
191    pub fn masked(mask: T) -> Self {
192        BitSetStrategy {
193            min: 0,
194            max: mask.len(),
195            mask: Some(mask),
196        }
197    }
198}
199
200impl<T: BitSetLike> Strategy for BitSetStrategy<T> {
201    type Tree = BitSetValueTree<T>;
202    type Value = T;
203
204    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
205        let mut inner = T::new_bitset(self.max);
206        for bit in self.min..self.max {
207            if self.mask.as_ref().map_or(true, |mask| mask.test(bit))
208                && runner.rng().gen()
209            {
210                inner.set(bit);
211            }
212        }
213
214        Ok(BitSetValueTree {
215            inner,
216            shrink: self.min,
217            prev_shrink: None,
218            min_count: 0,
219        })
220    }
221}
222
223/// Generates bit sets with a particular number of bits set.
224///
225/// Specifically, this strategy is given both a size range and a bit range. To
226/// produce a new value, it selects a size, then uniformly selects that many
227/// bits from within the bit range.
228///
229/// Shrinking happens as with [`BitSetStrategy`](struct.BitSetStrategy.html).
230#[derive(Clone, Debug)]
231#[must_use = "strategies do nothing unless used"]
232pub struct SampledBitSetStrategy<T: BitSetLike> {
233    size: SizeRange,
234    bits: SizeRange,
235    _marker: PhantomData<T>,
236}
237
238impl<T: BitSetLike> SampledBitSetStrategy<T> {
239    /// Create a strategy which generates values where bits within the bounds
240    /// given by `bits` may be set. The number of bits that are set is chosen
241    /// to be in the range given by `size`.
242    ///
243    /// Due to the generics, the functions in the typed submodules are usually
244    /// preferable to calling this directly.
245    ///
246    /// ## Panics
247    ///
248    /// Panics if `size` includes a value that is greater than the number of
249    /// bits in `bits`.
250    pub fn new(size: impl Into<SizeRange>, bits: impl Into<SizeRange>) -> Self {
251        let size = size.into();
252        let bits = bits.into();
253        size.assert_nonempty();
254
255        let available_bits = bits.end_excl() - bits.start();
256        assert!(
257            size.end_excl() <= available_bits + 1,
258            "Illegal SampledBitSetStrategy: have {} bits available, \
259             but requested size is {}..{}",
260            available_bits,
261            size.start(),
262            size.end_excl()
263        );
264        SampledBitSetStrategy {
265            size,
266            bits,
267            _marker: PhantomData,
268        }
269    }
270}
271
272impl<T: BitSetLike> Strategy for SampledBitSetStrategy<T> {
273    type Tree = BitSetValueTree<T>;
274    type Value = T;
275
276    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
277        let mut bits = T::new_bitset(self.bits.end_excl());
278        let count = sample_uniform_incl(
279            runner,
280            self.size.start(),
281            self.size.end_incl(),
282        );
283        if bits.len() < count {
284            panic!("not enough bits to sample");
285        }
286
287        for bit in self.bits.iter().choose_multiple(runner.rng(), count) {
288            bits.set(bit);
289        }
290
291        Ok(BitSetValueTree {
292            inner: bits,
293            shrink: self.bits.start(),
294            prev_shrink: None,
295            min_count: self.size.start(),
296        })
297    }
298}
299
300/// Value tree produced by `BitSetStrategy` and `SampledBitSetStrategy`.
301#[derive(Clone, Copy, Debug)]
302pub struct BitSetValueTree<T: BitSetLike> {
303    inner: T,
304    shrink: usize,
305    prev_shrink: Option<usize>,
306    min_count: usize,
307}
308
309impl<T: BitSetLike> ValueTree for BitSetValueTree<T> {
310    type Value = T;
311
312    fn current(&self) -> T {
313        self.inner.clone()
314    }
315
316    fn simplify(&mut self) -> bool {
317        if self.inner.count() <= self.min_count {
318            return false;
319        }
320
321        while self.shrink < self.inner.len() && !self.inner.test(self.shrink) {
322            self.shrink += 1;
323        }
324
325        if self.shrink >= self.inner.len() {
326            self.prev_shrink = None;
327            false
328        } else {
329            self.prev_shrink = Some(self.shrink);
330            self.inner.clear(self.shrink);
331            self.shrink += 1;
332            true
333        }
334    }
335
336    fn complicate(&mut self) -> bool {
337        if let Some(bit) = self.prev_shrink.take() {
338            self.inner.set(bit);
339            true
340        } else {
341            false
342        }
343    }
344}
345
346macro_rules! int_api {
347    ($typ:ident, $max:expr) => {
348        #[allow(missing_docs)]
349        pub mod $typ {
350            use super::*;
351
352            /// Generates integers where all bits may be set.
353            pub const ANY: BitSetStrategy<$typ> = BitSetStrategy {
354                min: 0,
355                max: $max,
356                mask: None,
357            };
358
359            /// Generates values where bits between the given bounds may be
360            /// set.
361            pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> {
362                BitSetStrategy::new(min, max)
363            }
364
365            /// Generates values where any bits set in `mask` (and no others)
366            /// may be set.
367            pub fn masked(mask: $typ) -> BitSetStrategy<$typ> {
368                BitSetStrategy::masked(mask)
369            }
370
371            /// Create a strategy which generates values where bits within the
372            /// bounds given by `bits` may be set. The number of bits that are
373            /// set is chosen to be in the range given by `size`.
374            ///
375            /// ## Panics
376            ///
377            /// Panics if `size` includes a value that is greater than the
378            /// number of bits in `bits`.
379            pub fn sampled(
380                size: impl Into<SizeRange>,
381                bits: impl Into<SizeRange>,
382            ) -> SampledBitSetStrategy<$typ> {
383                SampledBitSetStrategy::new(size, bits)
384            }
385        }
386    };
387}
388
389int_api!(u8, 8);
390int_api!(u16, 16);
391int_api!(u32, 32);
392int_api!(u64, 64);
393int_api!(i8, 8);
394int_api!(i16, 16);
395int_api!(i32, 32);
396int_api!(i64, 64);
397
398macro_rules! minimal_api {
399    ($md:ident, $typ:ty) => {
400        #[allow(missing_docs)]
401        pub mod $md {
402            use super::*;
403
404            /// Generates values where bits between the given bounds may be
405            /// set.
406            pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> {
407                BitSetStrategy::new(min, max)
408            }
409
410            /// Generates values where any bits set in `mask` (and no others)
411            /// may be set.
412            pub fn masked(mask: $typ) -> BitSetStrategy<$typ> {
413                BitSetStrategy::masked(mask)
414            }
415
416            /// Create a strategy which generates values where bits within the
417            /// bounds given by `bits` may be set. The number of bits that are
418            /// set is chosen to be in the range given by `size`.
419            ///
420            /// ## Panics
421            ///
422            /// Panics if `size` includes a value that is greater than the
423            /// number of bits in `bits`.
424            pub fn sampled(
425                size: impl Into<SizeRange>,
426                bits: impl Into<SizeRange>,
427            ) -> SampledBitSetStrategy<$typ> {
428                SampledBitSetStrategy::new(size, bits)
429            }
430        }
431    };
432}
433minimal_api!(usize, usize);
434minimal_api!(isize, isize);
435#[cfg(feature = "bit-set")]
436#[cfg_attr(docsrs, doc(cfg(feature = "bit-set")))]
437minimal_api!(bitset, BitSet);
438minimal_api!(bool_vec, Vec<bool>);
439
440pub(crate) mod varsize {
441    use super::*;
442    use core::iter::FromIterator;
443
444    #[cfg(feature = "bit-set")]
445    type Inner = BitSet;
446    #[cfg(not(feature = "bit-set"))]
447    type Inner = Vec<bool>;
448
449    /// A bit set is a set of bit flags.
450    #[derive(Debug, Clone)]
451    pub struct VarBitSet(Inner);
452
453    impl VarBitSet {
454        /// Create a bit set of `len` set values.
455        #[cfg(not(feature = "bit-set"))]
456        pub fn saturated(len: usize) -> Self {
457            Self(vec![true; len])
458        }
459
460        /// Create a bit set of `len` set values.
461        #[cfg(feature = "bit-set")]
462        pub fn saturated(len: usize) -> Self {
463            Self(BitSet::from_bit_vec(BitVec::from_elem(len, true)))
464        }
465
466        #[cfg(not(feature = "bit-set"))]
467        pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = usize> + 'a {
468            (0..self.len()).into_iter().filter(move |&ix| self.test(ix))
469        }
470
471        #[cfg(feature = "bit-set")]
472        pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = usize> + 'a {
473            self.0.iter()
474        }
475    }
476
477    impl BitSetLike for VarBitSet {
478        fn new_bitset(max: usize) -> Self {
479            VarBitSet(Inner::new_bitset(max))
480        }
481
482        fn len(&self) -> usize {
483            BitSetLike::len(&self.0)
484        }
485
486        fn test(&self, bit: usize) -> bool {
487            BitSetLike::test(&self.0, bit)
488        }
489
490        fn set(&mut self, bit: usize) {
491            BitSetLike::set(&mut self.0, bit);
492        }
493
494        fn clear(&mut self, bit: usize) {
495            BitSetLike::clear(&mut self.0, bit);
496        }
497
498        fn count(&self) -> usize {
499            BitSetLike::count(&self.0)
500        }
501    }
502
503    impl FromIterator<usize> for VarBitSet {
504        fn from_iter<T: IntoIterator<Item = usize>>(into_iter: T) -> Self {
505            let iter = into_iter.into_iter();
506            let lower_bound = iter.size_hint().0;
507            let mut bits = VarBitSet::new_bitset(lower_bound);
508            for bit in iter {
509                bits.set(bit);
510            }
511            bits
512        }
513    }
514
515    /*
516    pub(crate) fn between(min: usize, max: usize) -> BitSetStrategy<VarBitSet> {
517        BitSetStrategy::new(min, max)
518    }
519
520    pub(crate) fn masked(mask: VarBitSet) -> BitSetStrategy<VarBitSet> {
521        BitSetStrategy::masked(mask)
522    }
523    */
524
525    pub(crate) fn sampled(
526        size: impl Into<SizeRange>,
527        bits: impl Into<SizeRange>,
528    ) -> SampledBitSetStrategy<VarBitSet> {
529        SampledBitSetStrategy::new(size, bits)
530    }
531}
532
533pub use self::varsize::VarBitSet;
534
535#[cfg(test)]
536mod test {
537    use super::*;
538
539    #[test]
540    fn generates_values_in_range() {
541        let input = u32::between(4, 8);
542
543        let mut runner = TestRunner::default();
544        for _ in 0..256 {
545            let value = input.new_tree(&mut runner).unwrap().current();
546            assert!(0 == value & !0xF0u32, "Generate value {}", value);
547        }
548    }
549
550    #[test]
551    fn generates_values_in_mask() {
552        let mut accum = 0;
553
554        let mut runner = TestRunner::deterministic();
555        let input = u32::masked(0xdeadbeef);
556        for _ in 0..1024 {
557            accum |= input.new_tree(&mut runner).unwrap().current();
558        }
559
560        assert_eq!(0xdeadbeef, accum);
561    }
562
563    #[cfg(feature = "bit-set")]
564    #[test]
565    fn mask_bounds_for_bitset_correct() {
566        let mut seen_0 = false;
567        let mut seen_2 = false;
568
569        let mut mask = BitSet::new();
570        mask.insert(0);
571        mask.insert(2);
572
573        let mut runner = TestRunner::deterministic();
574        let input = bitset::masked(mask);
575        for _ in 0..32 {
576            let v = input.new_tree(&mut runner).unwrap().current();
577            seen_0 |= v.contains(0);
578            seen_2 |= v.contains(2);
579        }
580
581        assert!(seen_0);
582        assert!(seen_2);
583    }
584
585    #[test]
586    fn mask_bounds_for_vecbool_correct() {
587        let mut seen_0 = false;
588        let mut seen_2 = false;
589
590        let mask = vec![true, false, true, false];
591
592        let mut runner = TestRunner::deterministic();
593        let input = bool_vec::masked(mask);
594        for _ in 0..32 {
595            let v = input.new_tree(&mut runner).unwrap().current();
596            assert_eq!(4, v.len());
597            seen_0 |= v[0];
598            seen_2 |= v[2];
599        }
600
601        assert!(seen_0);
602        assert!(seen_2);
603    }
604
605    #[test]
606    fn shrinks_to_zero() {
607        let input = u32::between(4, 24);
608
609        let mut runner = TestRunner::default();
610        for _ in 0..256 {
611            let mut value = input.new_tree(&mut runner).unwrap();
612            let mut prev = value.current();
613            while value.simplify() {
614                let v = value.current();
615                assert!(
616                    1 == (prev & !v).count_ones(),
617                    "Shrank from {} to {}",
618                    prev,
619                    v
620                );
621                prev = v;
622            }
623
624            assert_eq!(0, value.current());
625        }
626    }
627
628    #[test]
629    fn complicates_to_previous() {
630        let input = u32::between(4, 24);
631
632        let mut runner = TestRunner::default();
633        for _ in 0..256 {
634            let mut value = input.new_tree(&mut runner).unwrap();
635            let orig = value.current();
636            if value.simplify() {
637                assert!(value.complicate());
638                assert_eq!(orig, value.current());
639            }
640        }
641    }
642
643    #[test]
644    fn sampled_selects_correct_sizes_and_bits() {
645        let input = u32::sampled(4..8, 10..20);
646        let mut seen_counts = [0; 32];
647        let mut seen_bits = [0; 32];
648
649        let mut runner = TestRunner::deterministic();
650        for _ in 0..2048 {
651            let value = input.new_tree(&mut runner).unwrap().current();
652            let count = value.count_ones() as usize;
653            assert!(count >= 4 && count < 8);
654            seen_counts[count] += 1;
655
656            for bit in 0..32 {
657                if 0 != value & (1 << bit) {
658                    assert!(bit >= 10 && bit < 20);
659                    seen_bits[bit] += value;
660                }
661            }
662        }
663
664        for i in 4..8 {
665            assert!(seen_counts[i] >= 256 && seen_counts[i] < 1024);
666        }
667
668        let least_seen_bit_count =
669            seen_bits[10..20].iter().cloned().min().unwrap();
670        let most_seen_bit_count =
671            seen_bits[10..20].iter().cloned().max().unwrap();
672        assert_eq!(1, most_seen_bit_count / least_seen_bit_count);
673    }
674
675    #[test]
676    fn sampled_doesnt_shrink_below_min_size() {
677        let input = u32::sampled(4..8, 10..20);
678
679        let mut runner = TestRunner::default();
680        for _ in 0..256 {
681            let mut value = input.new_tree(&mut runner).unwrap();
682            while value.simplify() {}
683
684            assert_eq!(4, value.current().count_ones());
685        }
686    }
687
688    #[test]
689    fn test_sanity() {
690        check_strategy_sanity(u32::masked(0xdeadbeef), None);
691    }
692}