blob: 35108ab07ba0523c39e880e2573eb6e410e343ab [file] [log] [blame]
//-
// Copyright 2017, 2018 The proptest developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Strategies for working with bit sets.
//!
//! Besides `BitSet` itself, this also defines strategies for all the primitive
//! integer types. These strategies are appropriate for integers which are used
//! as bit flags, etc; e.g., where the most reasonable simplification of `64`
//! is `0` (clearing one bit) and not `63` (clearing one bit but setting 6
//! others). For integers treated as numeric values, see the corresponding
//! modules of the `num` module instead.
use core::marker::PhantomData;
use core::mem;
use crate::std_facade::{fmt, Vec};
#[cfg(feature = "bit-set")]
use bit_set::BitSet;
use rand::{self, Rng, seq::IteratorRandom};
use crate::collection::SizeRange;
use crate::num::sample_uniform_incl;
use crate::strategy::*;
use crate::test_runner::*;
/// Trait for types which can be handled with `BitSetStrategy`.
#[cfg_attr(feature="cargo-clippy", allow(len_without_is_empty))]
pub trait BitSetLike : Clone + fmt::Debug {
/// Create a new value of `Self` with space for up to `max` bits, all
/// initialised to zero.
fn new_bitset(max: usize) -> Self;
/// Return an upper bound on the greatest bit set _plus one_.
fn len(&self) -> usize;
/// Test whether the given bit is set.
fn test(&self, ix: usize) -> bool;
/// Set the given bit.
fn set(&mut self, ix: usize);
/// Clear the given bit.
fn clear(&mut self, ix: usize);
/// Return the number of bits set.
///
/// This has a default for backwards compatibility, which simply does a
/// linear scan through the bits. Implementations are strongly encouraged
/// to override this.
fn count(&self) -> usize {
let mut n = 0;
for i in 0..self.len() {
if self.test(i) {
n += 1;
}
}
n
}
}
macro_rules! int_bitset {
($typ:ty) => {
impl BitSetLike for $typ {
fn new_bitset(_: usize) -> Self { 0 }
fn len(&self) -> usize { mem::size_of::<$typ>()*8 }
fn test(&self, ix: usize) -> bool {
0 != (*self & ((1 as $typ) << ix))
}
fn set(&mut self, ix: usize) {
*self |= (1 as $typ) << ix;
}
fn clear(&mut self, ix: usize) {
*self &= !((1 as $typ) << ix);
}
fn count(&self) -> usize {
self.count_ones() as usize
}
}
}
}
int_bitset!(u8);
int_bitset!(u16);
int_bitset!(u32);
int_bitset!(u64);
int_bitset!(usize);
int_bitset!(i8);
int_bitset!(i16);
int_bitset!(i32);
int_bitset!(i64);
int_bitset!(isize);
#[cfg(feature = "bit-set")]
impl BitSetLike for BitSet {
fn new_bitset(max: usize) -> Self {
BitSet::with_capacity(max)
}
fn len(&self) -> usize {
self.capacity()
}
fn test(&self, bit: usize) -> bool {
self.contains(bit)
}
fn set(&mut self, bit: usize) {
self.insert(bit);
}
fn clear(&mut self, bit: usize) {
self.remove(bit);
}
fn count(&self) -> usize {
self.len()
}
}
impl BitSetLike for Vec<bool> {
fn new_bitset(max: usize) -> Self {
vec![false; max]
}
fn len(&self) -> usize {
self.len()
}
fn test(&self, bit: usize) -> bool {
if bit >= self.len() {
false
} else {
self[bit]
}
}
fn set(&mut self, bit: usize) {
if bit >= self.len() {
self.resize(bit + 1, false);
}
self[bit] = true;
}
fn clear(&mut self, bit: usize) {
if bit < self.len() {
self[bit] = false;
}
}
fn count(&self) -> usize {
self.iter().filter(|&&b| b).count()
}
}
/// Generates values as a set of bits between the two bounds.
///
/// Values are generated by uniformly setting individual bits to 0
/// or 1 between the bounds. Shrinking iteratively clears bits.
#[must_use = "strategies do nothing unless used"]
#[derive(Clone, Copy, Debug)]
pub struct BitSetStrategy<T : BitSetLike> {
min: usize,
max: usize,
mask: Option<T>
}
impl<T : BitSetLike> BitSetStrategy<T> {
/// Create a strategy which generates values where bits between `min`
/// (inclusive) and `max` (exclusive) may be set.
///
/// Due to the generics, the functions in the typed submodules are usually
/// preferable to calling this directly.
pub fn new(min: usize, max: usize) -> Self {
BitSetStrategy {
min, max, mask: None,
}
}
/// Create a strategy which generates values where any bits set (and only
/// those bits) in `mask` may be set.
pub fn masked(mask: T) -> Self {
BitSetStrategy {
min: 0,
max: mask.len(),
mask: Some(mask)
}
}
}
impl<T : BitSetLike> Strategy for BitSetStrategy<T> {
type Tree = BitSetValueTree<T>;
type Value = T;
fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
let mut inner = T::new_bitset(self.max);
for bit in self.min..self.max {
if self.mask.as_ref().map_or(true, |mask| mask.test(bit)) &&
runner.rng().gen()
{
inner.set(bit);
}
}
Ok(BitSetValueTree {
inner,
shrink: self.min,
prev_shrink: None,
min_count: 0
})
}
}
/// Generates bit sets with a particular number of bits set.
///
/// Specifically, this strategy is given both a size range and a bit range. To
/// produce a new value, it selects a size, then uniformly selects that many
/// bits from within the bit range.
///
/// Shrinking happens as with [`BitSetStrategy`](struct.BitSetStrategy.html).
#[derive(Clone, Debug)]
#[must_use = "strategies do nothing unless used"]
pub struct SampledBitSetStrategy<T : BitSetLike> {
size: SizeRange,
bits: SizeRange,
_marker: PhantomData<T>,
}
impl<T : BitSetLike> SampledBitSetStrategy<T> {
/// Create a strategy which generates values where bits within the bounds
/// given by `bits` may be set. The number of bits that are set is chosen
/// to be in the range given by `size`.
///
/// Due to the generics, the functions in the typed submodules are usually
/// preferable to calling this directly.
///
/// ## Panics
///
/// Panics if `size` includes a value that is greater than the number of
/// bits in `bits`.
pub fn new(size: impl Into<SizeRange>, bits: impl Into<SizeRange>)
-> Self {
let size = size.into();
let bits = bits.into();
size.assert_nonempty();
let available_bits = bits.end_excl() - bits.start();
assert!(size.end_excl() <= available_bits + 1,
"Illegal SampledBitSetStrategy: have {} bits available, \
but requested size is {}..{}",
available_bits, size.start(), size.end_excl());
SampledBitSetStrategy {
size, bits, _marker: PhantomData
}
}
}
impl<T : BitSetLike> Strategy for SampledBitSetStrategy<T> {
type Tree = BitSetValueTree<T>;
type Value = T;
fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
let mut bits = T::new_bitset(self.bits.end_excl());
let count = sample_uniform_incl(
runner, self.size.start(), self.size.end_incl());
if bits.len() < count {
panic!("not enough bits to sample");
}
for bit in self.bits.iter().choose_multiple(runner.rng(), count) {
bits.set(bit);
}
Ok(BitSetValueTree {
inner: bits,
shrink: self.bits.start(),
prev_shrink: None,
min_count: self.size.start(),
})
}
}
/// Value tree produced by `BitSetStrategy` and `SampledBitSetStrategy`.
#[derive(Clone, Copy, Debug)]
pub struct BitSetValueTree<T : BitSetLike> {
inner: T,
shrink: usize,
prev_shrink: Option<usize>,
min_count: usize,
}
impl<T : BitSetLike> ValueTree for BitSetValueTree<T> {
type Value = T;
fn current(&self) -> T {
self.inner.clone()
}
fn simplify(&mut self) -> bool {
if self.inner.count() <= self.min_count {
return false;
}
while self.shrink < self.inner.len() &&
!self.inner.test(self.shrink)
{ self.shrink += 1; }
if self.shrink >= self.inner.len() {
self.prev_shrink = None;
false
} else {
self.prev_shrink = Some(self.shrink);
self.inner.clear(self.shrink);
self.shrink += 1;
true
}
}
fn complicate(&mut self) -> bool {
if let Some(bit) = self.prev_shrink.take() {
self.inner.set(bit);
true
} else {
false
}
}
}
macro_rules! int_api {
($typ:ident, $max:expr) => {
#[allow(missing_docs)]
pub mod $typ {
use super::*;
/// Generates integers where all bits may be set.
pub const ANY: BitSetStrategy<$typ> = BitSetStrategy {
min: 0,
max: $max,
mask: None,
};
/// Generates values where bits between the given bounds may be
/// set.
pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> {
BitSetStrategy::new(min, max)
}
/// Generates values where any bits set in `mask` (and no others)
/// may be set.
pub fn masked(mask: $typ) -> BitSetStrategy<$typ> {
BitSetStrategy::masked(mask)
}
/// Create a strategy which generates values where bits within the
/// bounds given by `bits` may be set. The number of bits that are
/// set is chosen to be in the range given by `size`.
///
/// ## Panics
///
/// Panics if `size` includes a value that is greater than the
/// number of bits in `bits`.
pub fn sampled(size: impl Into<SizeRange>, bits: impl Into<SizeRange>)
-> SampledBitSetStrategy<$typ> {
SampledBitSetStrategy::new(size, bits)
}
}
}
}
int_api!(u8, 8);
int_api!(u16, 16);
int_api!(u32, 32);
int_api!(u64, 64);
int_api!(i8, 8);
int_api!(i16, 16);
int_api!(i32, 32);
int_api!(i64, 64);
macro_rules! minimal_api {
($md:ident, $typ:ty) => {
#[allow(missing_docs)]
pub mod $md {
use super::*;
/// Generates values where bits between the given bounds may be
/// set.
pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> {
BitSetStrategy::new(min, max)
}
/// Generates values where any bits set in `mask` (and no others)
/// may be set.
pub fn masked(mask: $typ) -> BitSetStrategy<$typ> {
BitSetStrategy::masked(mask)
}
/// Create a strategy which generates values where bits within the
/// bounds given by `bits` may be set. The number of bits that are
/// set is chosen to be in the range given by `size`.
///
/// ## Panics
///
/// Panics if `size` includes a value that is greater than the
/// number of bits in `bits`.
pub fn sampled(size: impl Into<SizeRange>, bits: impl Into<SizeRange>)
-> SampledBitSetStrategy<$typ> {
SampledBitSetStrategy::new(size, bits)
}
}
}
}
minimal_api!(usize, usize);
minimal_api!(isize, isize);
#[cfg(feature = "bit-set")]
minimal_api!(bitset, BitSet);
minimal_api!(bool_vec, Vec<bool>);
pub(crate) mod varsize {
use super::*;
use core::iter::FromIterator;
#[cfg(feature = "bit-set")]
type Inner = BitSet;
#[cfg(not(feature = "bit-set"))]
type Inner = Vec<bool>;
#[derive(Debug, Clone)]
pub(crate) struct VarBitSet(Inner);
impl VarBitSet {
pub(crate) fn saturated(len: usize) -> Self {
(0..len).collect::<VarBitSet>()
}
#[cfg(not(feature = "bit-set"))]
pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = usize> + 'a {
(0..self.len()).into_iter().filter(move |&ix| self.test(ix))
}
#[cfg(feature = "bit-set")]
pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = usize> + 'a {
self.0.iter()
}
}
impl BitSetLike for VarBitSet {
fn new_bitset(max: usize) -> Self {
VarBitSet(Inner::new_bitset(max))
}
fn len(&self) -> usize {
BitSetLike::len(&self.0)
}
fn test(&self, bit: usize) -> bool {
BitSetLike::test(&self.0, bit)
}
fn set(&mut self, bit: usize) {
BitSetLike::set(&mut self.0, bit);
}
fn clear(&mut self, bit: usize) {
BitSetLike::clear(&mut self.0, bit);
}
fn count(&self) -> usize {
BitSetLike::count(&self.0)
}
}
impl FromIterator<usize> for VarBitSet {
fn from_iter<T : IntoIterator<Item = usize>>(iter: T) -> Self {
let mut bits = VarBitSet::new_bitset(0);
for bit in iter {
bits.set(bit);
}
bits
}
}
/*
pub(crate) fn between(min: usize, max: usize) -> BitSetStrategy<VarBitSet> {
BitSetStrategy::new(min, max)
}
pub(crate) fn masked(mask: VarBitSet) -> BitSetStrategy<VarBitSet> {
BitSetStrategy::masked(mask)
}
*/
pub(crate) fn sampled(size: impl Into<SizeRange>, bits: impl Into<SizeRange>)
-> SampledBitSetStrategy<VarBitSet> {
SampledBitSetStrategy::new(size, bits)
}
}
pub(crate) use self::varsize::VarBitSet;
#[cfg(test)]
mod test {
use super::*;
#[test]
fn generates_values_in_range() {
let input = u32::between(4, 8);
let mut runner = TestRunner::default();
for _ in 0..256 {
let value = input.new_tree(&mut runner).unwrap().current();
assert!(0 == value & !0xF0u32,
"Generate value {}", value);
}
}
#[test]
fn generates_values_in_mask() {
let mut accum = 0;
let mut runner = TestRunner::deterministic();
let input = u32::masked(0xdeadbeef);
for _ in 0..1024 {
accum |= input.new_tree(&mut runner).unwrap().current();
}
assert_eq!(0xdeadbeef, accum);
}
#[cfg(feature = "bit-set")]
#[test]
fn mask_bounds_for_bitset_correct() {
let mut seen_0 = false;
let mut seen_2 = false;
let mut mask = BitSet::new();
mask.insert(0);
mask.insert(2);
let mut runner = TestRunner::deterministic();
let input = bitset::masked(mask);
for _ in 0..32 {
let v = input.new_tree(&mut runner).unwrap().current();
seen_0 |= v.contains(0);
seen_2 |= v.contains(2);
}
assert!(seen_0);
assert!(seen_2);
}
#[test]
fn mask_bounds_for_vecbool_correct() {
let mut seen_0 = false;
let mut seen_2 = false;
let mask = vec![true, false, true, false];
let mut runner = TestRunner::deterministic();
let input = bool_vec::masked(mask);
for _ in 0..32 {
let v = input.new_tree(&mut runner).unwrap().current();
assert_eq!(4, v.len());
seen_0 |= v[0];
seen_2 |= v[2];
}
assert!(seen_0);
assert!(seen_2);
}
#[test]
fn shrinks_to_zero() {
let input = u32::between(4, 24);
let mut runner = TestRunner::default();
for _ in 0..256 {
let mut value = input.new_tree(&mut runner).unwrap();
let mut prev = value.current();
while value.simplify() {
let v = value.current();
assert!(1 == (prev & !v).count_ones(),
"Shrank from {} to {}", prev, v);
prev = v;
}
assert_eq!(0, value.current());
}
}
#[test]
fn complicates_to_previous() {
let input = u32::between(4, 24);
let mut runner = TestRunner::default();
for _ in 0..256 {
let mut value = input.new_tree(&mut runner).unwrap();
let orig = value.current();
if value.simplify() {
assert!(value.complicate());
assert_eq!(orig, value.current());
}
}
}
#[test]
fn sampled_selects_correct_sizes_and_bits() {
let input = u32::sampled(4..8, 10..20);
let mut seen_counts = [0; 32];
let mut seen_bits = [0; 32];
let mut runner = TestRunner::deterministic();
for _ in 0..2048 {
let value = input.new_tree(&mut runner).unwrap().current();
let count = value.count_ones() as usize;
assert!(count >= 4 && count < 8);
seen_counts[count] += 1;
for bit in 0..32 {
if 0 != value & (1 << bit) {
assert!(bit >= 10 && bit < 20);
seen_bits[bit] += value;
}
}
}
for i in 4..8 {
assert!(seen_counts[i] >= 256 && seen_counts[i] < 1024);
}
let least_seen_bit_count =
seen_bits[10..20].iter().cloned().min().unwrap();
let most_seen_bit_count =
seen_bits[10..20].iter().cloned().max().unwrap();
assert_eq!(1, most_seen_bit_count / least_seen_bit_count);
}
#[test]
fn sampled_doesnt_shrink_below_min_size() {
let input = u32::sampled(4..8, 10..20);
let mut runner = TestRunner::default();
for _ in 0..256 {
let mut value = input.new_tree(&mut runner).unwrap();
while value.simplify() { }
assert_eq!(4, value.current().count_ones());
}
}
#[test]
fn test_sanity() {
check_strategy_sanity(u32::masked(0xdeadbeef), None);
}
}