use super::generators::draw_and_print_value;
use super::{Collection, Generator, PrintableGenerator, TestCase, fnv1a_hash};
use crate::pretty::{PrettyPrintable, PrettyPrinter};
use crate::test_case::invalid_argument;
use std::borrow::Cow;
const SUBSEQUENCE_LABEL: u64 = fnv1a_hash(b"hegel:subsequence");
const PERMUTATION_LABEL: u64 = fnv1a_hash(b"hegel:permutation");
const SAMPLE_LABEL: u64 = fnv1a_hash(b"hegel:sample");
fn draw_index_sample(tc: &TestCase, n: usize, min_size: usize, max_size: usize) -> Vec<usize> {
let mut remaining: Vec<usize> = (0..n).collect();
let mut chosen = Vec::new();
let mut collection = Collection::new(tc, min_size, Some(max_size));
while !remaining.is_empty() && collection.more() {
let j = tc.generate_integer_i64(0, remaining.len() as i64 - 1) as usize;
chosen.push(remaining.remove(j));
}
chosen
}
pub struct SubsequenceGenerator<'a, T: Clone> {
elements: Cow<'a, [T]>,
min_size: usize,
max_size: Option<usize>,
}
impl<'a, T: Clone> SubsequenceGenerator<'a, T> {
pub fn min_size(mut self, min_size: usize) -> Self {
self.min_size = min_size;
self
}
pub fn max_size(mut self, max_size: usize) -> Self {
self.max_size = Some(max_size);
self
}
}
impl<'a, T: Clone + Send + Sync + 'a> Generator<Vec<T>> for SubsequenceGenerator<'a, T> {
fn do_draw(&self, tc: &TestCase) -> Vec<T> {
let n = self.elements.len();
if let Some(max) = self.max_size {
if self.min_size > max {
invalid_argument!("Cannot have max_size < min_size");
}
}
if self.min_size > n {
invalid_argument!(
"Cannot generate a subsequence: min_size {} is larger than the {} elements in the sequence",
self.min_size,
n
);
}
let max_size = self.max_size.map_or(n, |m| m.min(n));
tc.start_span(SUBSEQUENCE_LABEL);
let mut indices = draw_index_sample(tc, n, self.min_size, max_size);
tc.stop_span(false);
indices.sort_unstable();
indices
.into_iter()
.map(|i| self.elements[i].clone())
.collect()
}
}
impl<'a, T: Clone + Send + Sync + PrettyPrintable + 'a> PrintableGenerator<Vec<T>>
for SubsequenceGenerator<'a, T>
{
fn do_draw_and_print(&self, tc: &TestCase, printer: &mut PrettyPrinter) -> Vec<T> {
draw_and_print_value(self, tc, printer)
}
}
pub fn subsequences<'a, T, S>(elements: S) -> SubsequenceGenerator<'a, T>
where
T: Clone + Send + Sync,
S: Into<Cow<'a, [T]>>,
{
SubsequenceGenerator {
elements: elements.into(),
min_size: 0,
max_size: None,
}
}
pub struct PermutationGenerator<'a, T: Clone> {
elements: Cow<'a, [T]>,
}
impl<'a, T: Clone + Send + Sync + 'a> Generator<Vec<T>> for PermutationGenerator<'a, T> {
fn do_draw(&self, tc: &TestCase) -> Vec<T> {
let n = self.elements.len();
tc.start_span(PERMUTATION_LABEL);
let indices = draw_index_sample(tc, n, n, n);
tc.stop_span(false);
indices
.into_iter()
.map(|i| self.elements[i].clone())
.collect()
}
}
impl<'a, T: Clone + Send + Sync + PrettyPrintable + 'a> PrintableGenerator<Vec<T>>
for PermutationGenerator<'a, T>
{
fn do_draw_and_print(&self, tc: &TestCase, printer: &mut PrettyPrinter) -> Vec<T> {
draw_and_print_value(self, tc, printer)
}
}
pub fn permutations<'a, T, S>(elements: S) -> PermutationGenerator<'a, T>
where
T: Clone + Send + Sync,
S: Into<Cow<'a, [T]>>,
{
PermutationGenerator {
elements: elements.into(),
}
}
pub struct SampleGenerator<'a, T: Clone> {
elements: Cow<'a, [T]>,
min_size: usize,
max_size: Option<usize>,
replacement: bool,
}
impl<'a, T: Clone> SampleGenerator<'a, T> {
pub fn min_size(mut self, min_size: usize) -> Self {
self.min_size = min_size;
self
}
pub fn max_size(mut self, max_size: usize) -> Self {
self.max_size = Some(max_size);
self
}
pub fn with_replacement(mut self) -> Self {
self.replacement = true;
self
}
pub fn without_replacement(mut self) -> Self {
self.replacement = false;
self
}
}
impl<'a, T: Clone + Send + Sync + 'a> Generator<Vec<T>> for SampleGenerator<'a, T> {
fn do_draw(&self, tc: &TestCase) -> Vec<T> {
let n = self.elements.len();
if let Some(max) = self.max_size {
if self.min_size > max {
invalid_argument!("Cannot have max_size < min_size");
}
}
if self.replacement {
if n == 0 && self.min_size > 0 {
invalid_argument!("Cannot generate a non-empty sample from an empty sequence");
}
let max_size = if n == 0 { Some(0) } else { self.max_size };
tc.start_span(SAMPLE_LABEL);
let mut collection = Collection::new(tc, self.min_size, max_size);
let mut result = Vec::new();
while collection.more() {
let i = tc.generate_integer_i64(0, n as i64 - 1) as usize;
result.push(self.elements[i].clone());
}
tc.stop_span(false);
result
} else {
if self.min_size > n {
invalid_argument!(
"Cannot generate a sample without replacement: min_size {} is larger than the {} elements in the sequence",
self.min_size,
n
);
}
let max_size = self.max_size.map_or(n, |m| m.min(n));
tc.start_span(SAMPLE_LABEL);
let indices = draw_index_sample(tc, n, self.min_size, max_size);
tc.stop_span(false);
indices
.into_iter()
.map(|i| self.elements[i].clone())
.collect()
}
}
}
impl<'a, T: Clone + Send + Sync + PrettyPrintable + 'a> PrintableGenerator<Vec<T>>
for SampleGenerator<'a, T>
{
fn do_draw_and_print(&self, tc: &TestCase, printer: &mut PrettyPrinter) -> Vec<T> {
draw_and_print_value(self, tc, printer)
}
}
pub fn samples<'a, T, S>(elements: S) -> SampleGenerator<'a, T>
where
T: Clone + Send + Sync,
S: Into<Cow<'a, [T]>>,
{
SampleGenerator {
elements: elements.into(),
min_size: 0,
max_size: None,
replacement: true,
}
}