Skip to main content

proptest/
bits.rs

1//-
2// Copyright 2017, 2018, 2026 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!(u128);
93int_bitset!(usize);
94int_bitset!(i8);
95int_bitset!(i16);
96int_bitset!(i32);
97int_bitset!(i64);
98int_bitset!(i128);
99int_bitset!(isize);
100
101#[cfg(feature = "bit-set")]
102#[cfg_attr(docsrs, doc(cfg(feature = "bit-set")))]
103impl BitSetLike for BitSet {
104    fn new_bitset(max: usize) -> Self {
105        BitSet::with_capacity(max)
106    }
107
108    fn len(&self) -> usize {
109        self.capacity()
110    }
111
112    fn test(&self, bit: usize) -> bool {
113        self.contains(bit)
114    }
115
116    fn set(&mut self, bit: usize) {
117        self.insert(bit);
118    }
119
120    fn clear(&mut self, bit: usize) {
121        self.remove(bit);
122    }
123
124    fn count(&self) -> usize {
125        self.len()
126    }
127}
128
129impl BitSetLike for Vec<bool> {
130    fn new_bitset(max: usize) -> Self {
131        vec![false; max]
132    }
133
134    fn len(&self) -> usize {
135        self.len()
136    }
137
138    fn test(&self, bit: usize) -> bool {
139        if bit >= self.len() {
140            false
141        } else {
142            self[bit]
143        }
144    }
145
146    fn set(&mut self, bit: usize) {
147        if bit >= self.len() {
148            self.resize(bit + 1, false);
149        }
150
151        self[bit] = true;
152    }
153
154    fn clear(&mut self, bit: usize) {
155        if bit < self.len() {
156            self[bit] = false;
157        }
158    }
159
160    fn count(&self) -> usize {
161        self.iter().filter(|&&b| b).count()
162    }
163}
164
165/// Generates values as a set of bits between the two bounds.
166///
167/// Values are generated by uniformly setting individual bits to 0
168/// or 1 between the bounds. Shrinking iteratively clears bits.
169#[must_use = "strategies do nothing unless used"]
170#[derive(Clone, Copy, Debug)]
171pub struct BitSetStrategy<T: BitSetLike> {
172    min: usize,
173    max: usize,
174    mask: Option<T>,
175}
176
177impl<T: BitSetLike> BitSetStrategy<T> {
178    /// Create a strategy which generates values where bits between `min`
179    /// (inclusive) and `max` (exclusive) may be set.
180    ///
181    /// Due to the generics, the functions in the typed submodules are usually
182    /// preferable to calling this directly.
183    pub fn new(min: usize, max: usize) -> Self {
184        BitSetStrategy {
185            min,
186            max,
187            mask: None,
188        }
189    }
190
191    /// Create a strategy which generates values where any bits set (and only
192    /// those bits) in `mask` may be set.
193    pub fn masked(mask: T) -> Self {
194        BitSetStrategy {
195            min: 0,
196            max: mask.len(),
197            mask: Some(mask),
198        }
199    }
200}
201
202impl<T: BitSetLike> Strategy for BitSetStrategy<T> {
203    type Tree = BitSetValueTree<T>;
204    type Value = T;
205
206    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
207        let mut inner = T::new_bitset(self.max);
208        for bit in self.min..self.max {
209            if self.mask.as_ref().map_or(true, |mask| mask.test(bit))
210                && runner.rng().random()
211            {
212                inner.set(bit);
213            }
214        }
215
216        Ok(BitSetValueTree {
217            inner,
218            shrink: self.min,
219            prev_shrink: None,
220            min_count: 0,
221        })
222    }
223}
224
225/// Generates bit sets with a particular number of bits set.
226///
227/// Specifically, this strategy is given both a size range and a bit range. To
228/// produce a new value, it selects a size, then uniformly selects that many
229/// bits from within the bit range.
230///
231/// Shrinking happens as with [`BitSetStrategy`](struct.BitSetStrategy.html).
232#[derive(Clone, Debug)]
233#[must_use = "strategies do nothing unless used"]
234pub struct SampledBitSetStrategy<T: BitSetLike> {
235    size: SizeRange,
236    bits: SizeRange,
237    _marker: PhantomData<T>,
238}
239
240impl<T: BitSetLike> SampledBitSetStrategy<T> {
241    /// Create a strategy which generates values where bits within the bounds
242    /// given by `bits` may be set. The number of bits that are set is chosen
243    /// to be in the range given by `size`.
244    ///
245    /// Due to the generics, the functions in the typed submodules are usually
246    /// preferable to calling this directly.
247    ///
248    /// ## Panics
249    ///
250    /// Panics if `size` includes a value that is greater than the number of
251    /// bits in `bits`.
252    pub fn new(size: impl Into<SizeRange>, bits: impl Into<SizeRange>) -> Self {
253        let size = size.into();
254        let bits = bits.into();
255        size.assert_nonempty();
256
257        let available_bits = bits.end_excl() - bits.start();
258        assert!(
259            size.end_excl() <= available_bits + 1,
260            "Illegal SampledBitSetStrategy: have {} bits available, \
261             but requested size is {}..{}",
262            available_bits,
263            size.start(),
264            size.end_excl()
265        );
266        SampledBitSetStrategy {
267            size,
268            bits,
269            _marker: PhantomData,
270        }
271    }
272}
273
274impl<T: BitSetLike> Strategy for SampledBitSetStrategy<T> {
275    type Tree = BitSetValueTree<T>;
276    type Value = T;
277
278    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
279        let mut bits = T::new_bitset(self.bits.end_excl());
280        let count = sample_uniform_incl(
281            runner,
282            self.size.start(),
283            self.size.end_incl(),
284        );
285        if bits.len() < count {
286            panic!("not enough bits to sample");
287        }
288
289        for bit in self.bits.iter().choose_multiple(runner.rng(), count) {
290            bits.set(bit);
291        }
292
293        Ok(BitSetValueTree {
294            inner: bits,
295            shrink: self.bits.start(),
296            prev_shrink: None,
297            min_count: self.size.start(),
298        })
299    }
300}
301
302/// Value tree produced by `BitSetStrategy` and `SampledBitSetStrategy`.
303#[derive(Clone, Copy, Debug)]
304pub struct BitSetValueTree<T: BitSetLike> {
305    inner: T,
306    shrink: usize,
307    prev_shrink: Option<usize>,
308    min_count: usize,
309}
310
311impl<T: BitSetLike> ValueTree for BitSetValueTree<T> {
312    type Value = T;
313
314    fn current(&self) -> T {
315        self.inner.clone()
316    }
317
318    fn simplify(&mut self) -> bool {
319        if self.inner.count() <= self.min_count {
320            return false;
321        }
322
323        while self.shrink < self.inner.len() && !self.inner.test(self.shrink) {
324            self.shrink += 1;
325        }
326
327        if self.shrink >= self.inner.len() {
328            self.prev_shrink = None;
329            false
330        } else {
331            self.prev_shrink = Some(self.shrink);
332            self.inner.clear(self.shrink);
333            self.shrink += 1;
334            true
335        }
336    }
337
338    fn complicate(&mut self) -> bool {
339        if let Some(bit) = self.prev_shrink.take() {
340            self.inner.set(bit);
341            true
342        } else {
343            false
344        }
345    }
346}
347
348macro_rules! int_api {
349    ($typ:ident, $max:expr) => {
350        #[allow(missing_docs)]
351        pub mod $typ {
352            use super::*;
353
354            /// Generates integers where all bits may be set.
355            pub const ANY: BitSetStrategy<$typ> = BitSetStrategy {
356                min: 0,
357                max: $max,
358                mask: None,
359            };
360
361            /// Generates values where bits between the given bounds may be
362            /// set.
363            pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> {
364                BitSetStrategy::new(min, max)
365            }
366
367            /// Generates values where any bits set in `mask` (and no others)
368            /// may be set.
369            pub fn masked(mask: $typ) -> BitSetStrategy<$typ> {
370                BitSetStrategy::masked(mask)
371            }
372
373            /// Create a strategy which generates values where bits within the
374            /// bounds given by `bits` may be set. The number of bits that are
375            /// set is chosen to be in the range given by `size`.
376            ///
377            /// ## Panics
378            ///
379            /// Panics if `size` includes a value that is greater than the
380            /// number of bits in `bits`.
381            pub fn sampled(
382                size: impl Into<SizeRange>,
383                bits: impl Into<SizeRange>,
384            ) -> SampledBitSetStrategy<$typ> {
385                SampledBitSetStrategy::new(size, bits)
386            }
387        }
388    };
389}
390
391int_api!(u8, 8);
392int_api!(u16, 16);
393int_api!(u32, 32);
394int_api!(u64, 64);
395int_api!(u128, 128);
396int_api!(i8, 8);
397int_api!(i16, 16);
398int_api!(i32, 32);
399int_api!(i64, 64);
400int_api!(i128, 128);
401
402macro_rules! minimal_api {
403    ($md:ident, $typ:ty) => {
404        #[allow(missing_docs)]
405        pub mod $md {
406            use super::*;
407
408            /// Generates values where bits between the given bounds may be
409            /// set.
410            pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> {
411                BitSetStrategy::new(min, max)
412            }
413
414            /// Generates values where any bits set in `mask` (and no others)
415            /// may be set.
416            pub fn masked(mask: $typ) -> BitSetStrategy<$typ> {
417                BitSetStrategy::masked(mask)
418            }
419
420            /// Create a strategy which generates values where bits within the
421            /// bounds given by `bits` may be set. The number of bits that are
422            /// set is chosen to be in the range given by `size`.
423            ///
424            /// ## Panics
425            ///
426            /// Panics if `size` includes a value that is greater than the
427            /// number of bits in `bits`.
428            pub fn sampled(
429                size: impl Into<SizeRange>,
430                bits: impl Into<SizeRange>,
431            ) -> SampledBitSetStrategy<$typ> {
432                SampledBitSetStrategy::new(size, bits)
433            }
434        }
435    };
436}
437minimal_api!(usize, usize);
438minimal_api!(isize, isize);
439#[cfg(feature = "bit-set")]
440#[cfg_attr(docsrs, doc(cfg(feature = "bit-set")))]
441minimal_api!(bitset, BitSet);
442minimal_api!(bool_vec, Vec<bool>);
443
444pub(crate) mod varsize {
445    use super::*;
446    use core::iter::FromIterator;
447
448    #[cfg(feature = "bit-set")]
449    type Inner = BitSet;
450    #[cfg(not(feature = "bit-set"))]
451    type Inner = Vec<bool>;
452
453    /// A bit set is a set of bit flags.
454    #[derive(Debug, Clone)]
455    pub struct VarBitSet(Inner);
456
457    impl VarBitSet {
458        /// Create a bit set of `len` set values.
459        #[cfg(not(feature = "bit-set"))]
460        pub fn saturated(len: usize) -> Self {
461            Self(vec![true; len])
462        }
463
464        /// Create a bit set of `len` set values.
465        #[cfg(feature = "bit-set")]
466        pub fn saturated(len: usize) -> Self {
467            Self(BitSet::from_bit_vec(BitVec::from_elem(len, true)))
468        }
469
470        #[cfg(not(feature = "bit-set"))]
471        pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = usize> + 'a {
472            (0..self.len()).into_iter().filter(move |&ix| self.test(ix))
473        }
474
475        #[cfg(feature = "bit-set")]
476        pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = usize> + 'a {
477            self.0.iter()
478        }
479    }
480
481    impl BitSetLike for VarBitSet {
482        fn new_bitset(max: usize) -> Self {
483            VarBitSet(Inner::new_bitset(max))
484        }
485
486        fn len(&self) -> usize {
487            BitSetLike::len(&self.0)
488        }
489
490        fn test(&self, bit: usize) -> bool {
491            BitSetLike::test(&self.0, bit)
492        }
493
494        fn set(&mut self, bit: usize) {
495            BitSetLike::set(&mut self.0, bit);
496        }
497
498        fn clear(&mut self, bit: usize) {
499            BitSetLike::clear(&mut self.0, bit);
500        }
501
502        fn count(&self) -> usize {
503            BitSetLike::count(&self.0)
504        }
505    }
506
507    impl FromIterator<usize> for VarBitSet {
508        fn from_iter<T: IntoIterator<Item = usize>>(into_iter: T) -> Self {
509            let iter = into_iter.into_iter();
510            let lower_bound = iter.size_hint().0;
511            let mut bits = VarBitSet::new_bitset(lower_bound);
512            for bit in iter {
513                bits.set(bit);
514            }
515            bits
516        }
517    }
518
519    /*
520    pub(crate) fn between(min: usize, max: usize) -> BitSetStrategy<VarBitSet> {
521        BitSetStrategy::new(min, max)
522    }
523
524    pub(crate) fn masked(mask: VarBitSet) -> BitSetStrategy<VarBitSet> {
525        BitSetStrategy::masked(mask)
526    }
527    */
528
529    pub(crate) fn sampled(
530        size: impl Into<SizeRange>,
531        bits: impl Into<SizeRange>,
532    ) -> SampledBitSetStrategy<VarBitSet> {
533        SampledBitSetStrategy::new(size, bits)
534    }
535}
536
537pub use self::varsize::VarBitSet;
538
539#[cfg(test)]
540mod test {
541    use super::*;
542
543    #[test]
544    fn generates_values_in_range() {
545        let input = u32::between(4, 8);
546
547        let mut runner = TestRunner::default();
548        for _ in 0..256 {
549            let value = input.new_tree(&mut runner).unwrap().current();
550            assert!(0 == value & !0xF0u32, "Generate value {}", value);
551        }
552    }
553
554    #[test]
555    fn generates_values_in_mask() {
556        let mut accum = 0;
557
558        let mut runner = TestRunner::deterministic();
559        let input = u32::masked(0xdeadbeef);
560        for _ in 0..1024 {
561            accum |= input.new_tree(&mut runner).unwrap().current();
562        }
563
564        assert_eq!(0xdeadbeef, accum);
565    }
566
567    #[cfg(feature = "bit-set")]
568    #[test]
569    fn mask_bounds_for_bitset_correct() {
570        let mut seen_0 = false;
571        let mut seen_2 = false;
572
573        let mut mask = BitSet::new();
574        mask.insert(0);
575        mask.insert(2);
576
577        let mut runner = TestRunner::deterministic();
578        let input = bitset::masked(mask);
579        for _ in 0..32 {
580            let v = input.new_tree(&mut runner).unwrap().current();
581            seen_0 |= v.contains(0);
582            seen_2 |= v.contains(2);
583        }
584
585        assert!(seen_0);
586        assert!(seen_2);
587    }
588
589    #[test]
590    fn mask_bounds_for_vecbool_correct() {
591        let mut seen_0 = false;
592        let mut seen_2 = false;
593
594        let mask = vec![true, false, true, false];
595
596        let mut runner = TestRunner::deterministic();
597        let input = bool_vec::masked(mask);
598        for _ in 0..32 {
599            let v = input.new_tree(&mut runner).unwrap().current();
600            assert_eq!(4, v.len());
601            seen_0 |= v[0];
602            seen_2 |= v[2];
603        }
604
605        assert!(seen_0);
606        assert!(seen_2);
607    }
608
609    #[test]
610    fn shrinks_to_zero() {
611        let input = u32::between(4, 24);
612
613        let mut runner = TestRunner::default();
614        for _ in 0..256 {
615            let mut value = input.new_tree(&mut runner).unwrap();
616            let mut prev = value.current();
617            while value.simplify() {
618                let v = value.current();
619                assert!(
620                    1 == (prev & !v).count_ones(),
621                    "Shrank from {} to {}",
622                    prev,
623                    v
624                );
625                prev = v;
626            }
627
628            assert_eq!(0, value.current());
629        }
630    }
631
632    #[test]
633    fn complicates_to_previous() {
634        let input = u32::between(4, 24);
635
636        let mut runner = TestRunner::default();
637        for _ in 0..256 {
638            let mut value = input.new_tree(&mut runner).unwrap();
639            let orig = value.current();
640            if value.simplify() {
641                assert!(value.complicate());
642                assert_eq!(orig, value.current());
643            }
644        }
645    }
646
647    #[test]
648    fn sampled_selects_correct_sizes_and_bits() {
649        let input = u32::sampled(4..8, 10..20);
650        let mut seen_counts = [0; 32];
651        let mut seen_bits = [0; 32];
652
653        let mut runner = TestRunner::deterministic();
654        for _ in 0..2048 {
655            let value = input.new_tree(&mut runner).unwrap().current();
656            let count = value.count_ones() as usize;
657            assert!(count >= 4 && count < 8);
658            seen_counts[count] += 1;
659
660            for bit in 0..32 {
661                if 0 != value & (1 << bit) {
662                    assert!(bit >= 10 && bit < 20);
663                    seen_bits[bit] += value;
664                }
665            }
666        }
667
668        for i in 4..8 {
669            assert!(seen_counts[i] >= 256 && seen_counts[i] < 1024);
670        }
671
672        let least_seen_bit_count =
673            seen_bits[10..20].iter().cloned().min().unwrap();
674        let most_seen_bit_count =
675            seen_bits[10..20].iter().cloned().max().unwrap();
676        assert_eq!(1, most_seen_bit_count / least_seen_bit_count);
677    }
678
679    #[test]
680    fn sampled_doesnt_shrink_below_min_size() {
681        let input = u32::sampled(4..8, 10..20);
682
683        let mut runner = TestRunner::default();
684        for _ in 0..256 {
685            let mut value = input.new_tree(&mut runner).unwrap();
686            while value.simplify() {}
687
688            assert_eq!(4, value.current().count_ones());
689        }
690    }
691
692    #[test]
693    fn test_sanity() {
694        check_strategy_sanity(u32::masked(0xdeadbeef), None);
695    }
696
697    #[test]
698    fn u128_generates_values_in_range() {
699        let input = u128::between(64, 128);
700
701        let mut runner = TestRunner::default();
702        for _ in 0..256 {
703            let value = input.new_tree(&mut runner).unwrap().current();
704            // Only bits 64..128 should be set
705            assert!(
706                0 == value & ((1u128 << 64) - 1),
707                "Generated value has low bits set: {}",
708                value
709            );
710        }
711    }
712
713    #[test]
714    fn u128_shrinks_to_zero() {
715        let input = u128::between(64, 128);
716
717        let mut runner = TestRunner::default();
718        for _ in 0..256 {
719            let mut value = input.new_tree(&mut runner).unwrap();
720            while value.simplify() {}
721            assert_eq!(0, value.current());
722        }
723    }
724
725    #[test]
726    fn i128_generates_values_in_mask() {
727        let mut accum: i128 = 0;
728        let mask: i128 = 0x0123_4567_89ab_cdef_0123_4567_89ab_cdef;
729
730        let mut runner = TestRunner::deterministic();
731        let input = i128::masked(mask);
732        for _ in 0..1024 {
733            accum |= input.new_tree(&mut runner).unwrap().current();
734        }
735
736        assert_eq!(mask, accum);
737    }
738
739    #[test]
740    fn u128_test_sanity() {
741        check_strategy_sanity(
742            u128::masked(0xdeadbeef_cafebabe_12345678_9abcdef0),
743            None,
744        );
745    }
746}