use crate::reversal::dynamic_program::{AsFilterFn, CallType, Invertible, ReversalError};
use crate::reversal::java::java_calls::Range::{Equals, Full, Inverted, Normal};
use crate::reversal::java::{java_random, java_random_reverser};
use crate::reversal::random_reverser::RandomReverser;
use crate::util::Random;
use malachite::base::num::basic::traits::{One, Zero};
use std::fmt::Debug;
use std::ops::Rem;
use std::rc::Rc;
macro_rules! builder {
($name: ident, $java_name: literal, $bounds: literal, $ty: ty, $calls: literal, $lower_bound: expr, $upper_bound: expr, $precision: expr, $next_up: expr, $next_down: expr, $add_to_reverser_fn: expr) => {
#[doc= concat!("Creates a new builder equivalent to ", $java_name, ".<br>This builder's bounds are `", $bounds, "`.")]
pub fn $name() -> RangeCallTypeBuilder<$ty> {
RangeCallTypeBuilder {
calls: $calls,
lower_bound: $lower_bound,
upper_bound: $upper_bound,
precision: $precision,
next_up: Box::new($next_up),
next_down: Box::new($next_down),
random_call: Rc::new(java_random::$name),
add_to_reverser_fn: Box::new($add_to_reverser_fn),
}
}
};
}
pub fn next_boolean() -> BooleanCallTypeBuilder { BooleanCallTypeBuilder {} }
builder!(next_int, "nextInt()", "[i32::MIN, i32::MAX]", i32, 1, i32::MIN, i32::MAX, 1, |i| i + 1, |i| i - 1, java_random_reverser::add_next_int_call);
builder!(next_long, "nextLong()", "[i64::MIN, i64::MAX]", i64, 2, i64::MIN, i64::MAX, 1, |i| i + 1, |i| i - 1, java_random_reverser::add_next_long_call);
builder!(next_float, "nextFloat()", "[0, 1)", f32, 1, f32::ZERO, f32::ONE.next_down(), 1_f32 / (1 << 24) as f32, f32::next_up, f32::next_down, java_random_reverser::add_next_float_call);
builder!(next_double, "nextDouble()", "[0, 1)", f64, 2, f64::ZERO, f64::ONE.next_down(), 1_f64 / (1_i64 << 24) as f64, f64::next_up, f64::next_down, java_random_reverser::add_next_double_call);
pub fn next_bound_int(bound: i32) -> Result<RangeCallTypeBuilder<i32>, ReversalError> {
if bound < 1 {
return Err(ReversalError::TooSmallBound);
}
Ok(RangeCallTypeBuilder {
calls: 1,
lower_bound: 0,
upper_bound: bound - 1,
precision: 1,
next_up: Box::new(|i| i + 1),
next_down: Box::new(|i| i - 1),
random_call: Rc::new(move |random| java_random::next_bound_int(random, bound)),
add_to_reverser_fn: Box::new(move |reverser, min, max| {
java_random_reverser::add_bound_next_int_call(reverser, bound, min, max)
}),
})
}
pub struct BooleanCallTypeBuilder {}
impl BooleanCallTypeBuilder {
pub fn equal_to(self, value: bool) -> Box<BooleanCallType> {
Box::new(BooleanCallType { value })
}
pub fn not_equal_to(self, value: bool) -> Box<BooleanCallType> {
Box::new(BooleanCallType { value: !value })
}
}
pub struct BooleanCallType {
value: bool,
}
impl CallType for BooleanCallType {
fn num_calls(&self) -> i64 {
1
}
fn add_to(&self, reverser: &mut RandomReverser) -> Result<(), ReversalError> {
java_random_reverser::add_next_boolean_call(reverser, self.value);
Ok(())
}
}
impl AsFilterFn for BooleanCallType {
fn num_calls(&self) -> i64 {
1
}
fn as_filter_fn(&self) -> Result<Box<dyn Fn(&mut Random) -> bool>, ReversalError> {
let value = self.value;
Ok(Box::new(move |r| java_random::next_boolean(r) == value))
}
}
impl Invertible for BooleanCallType {
fn invert(mut self) -> Box<Self> {
self.value = !self.value;
Box::new(self)
}
}
#[derive(Clone)]
enum Range<T> {
Full,
Equals(T),
Normal(T, T),
Inverted(Box<Range<T>>),
}
pub struct RangeCallTypeBuilder<T> {
calls: i64,
lower_bound: T,
upper_bound: T,
precision: T,
next_up: Box<dyn Fn(T) -> T>,
next_down: Box<dyn Fn(T) -> T>,
random_call: Rc<dyn Fn(&mut Random) -> T>,
add_to_reverser_fn: Box<dyn Fn(&mut RandomReverser, Vec<T>, Vec<T>)>,
}
impl<T: Copy + Debug + PartialOrd + From<u8> + Rem<T, Output = T>> RangeCallTypeBuilder<T> {
fn check_precision(&self, name: &'static str, value: T) {
if value % self.precision != 0.into() {
eprintln!(
"Value of {} call is too precise, the last two bits will be rounded up!",
name
);
}
}
pub fn equal_to(self, value: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
self.check_precision("equal_to", value);
self.inclusive_range(value, value)
}
pub fn less_than(self, value: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
self.check_precision("less_than", value);
let lower_bound = self.lower_bound;
let upper_bound = (&self.next_down)(value);
self.inclusive_range(lower_bound, upper_bound)
}
pub fn less_than_eq(self, value: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
self.check_precision("less_than_eq", value);
let lower_bound = self.lower_bound;
self.inclusive_range(lower_bound, value)
}
pub fn greater_than(self, value: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
self.check_precision("greater_than", value);
let lower_bound = (&self.next_up)(value);
let upper_bound = self.upper_bound;
self.inclusive_range(lower_bound, upper_bound)
}
pub fn greater_than_eq(self, value: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
self.check_precision("greater_than_eq", value);
let upper_bound = self.upper_bound;
self.inclusive_range(value, upper_bound)
}
pub fn range(
self,
mut min: T,
mut max: T,
min_exclusive: bool,
max_exclusive: bool,
) -> Result<Box<RangeCallType<T>>, ReversalError> {
self.check_precision("range (min)", min);
self.check_precision("range (min)", max);
if max == min && (min_exclusive || max_exclusive) {
return Err(ReversalError::RangeIsEmpty);
} else if max < min {
return Err(ReversalError::MaxLowerThanMin);
}
if min_exclusive {
min = (&self.next_up)(min);
}
if max_exclusive {
max = (&self.next_down)(max);
}
self.inclusive_range(min, max)
}
fn inclusive_range(self, min: T, max: T) -> Result<Box<RangeCallType<T>>, ReversalError> {
if min < self.lower_bound {
return Err(ReversalError::MinLessThanLowerBound);
} else if max > self.upper_bound {
return Err(ReversalError::MaxGreaterThanUpperBound);
}
Ok(Box::new(RangeCallType {
range: {
if min == self.lower_bound && max == self.upper_bound {
Full
} else if min == max {
Equals(min)
} else {
Normal(min, max)
}
},
processor: self,
}))
}
}
pub struct RangeCallType<T> {
processor: RangeCallTypeBuilder<T>,
range: Range<T>,
}
impl<T: Copy + Debug + PartialOrd + From<u8> + Rem<T, Output = T> + 'static> CallType
for RangeCallType<T>
{
fn num_calls(&self) -> i64 {
self.processor.calls
}
fn add_to(&self, reverser: &mut RandomReverser) -> Result<(), ReversalError> {
let p = &self.processor;
match &self.range {
Full => reverser.add_unmeasured_seeds(p.calls),
Equals(value) => (p.add_to_reverser_fn)(reverser, vec![*value], vec![*value]),
Normal(min, max) => (p.add_to_reverser_fn)(reverser, vec![*min], vec![*max]),
Inverted(inner) => {
macro_rules! add_arbitrary_bound {
($min: expr, $max: expr) => {
let next_down = (p.next_down)($min);
let next_up = (p.next_up)($max);
(p.add_to_reverser_fn)(
reverser,
vec![p.lower_bound, next_up],
vec![next_down, p.upper_bound],
);
};
}
match **inner {
Full => return Err(ReversalError::RangeIsEmpty),
Equals(value) => {
if value == p.lower_bound {
(p.add_to_reverser_fn)(
reverser,
vec![(p.next_up)(p.lower_bound)],
vec![p.upper_bound],
)
} else if value == p.upper_bound {
(p.add_to_reverser_fn)(
reverser,
vec![p.lower_bound],
vec![(p.next_down)(p.upper_bound)],
)
}
add_arbitrary_bound!(value, value);
}
Normal(min, max) => {
add_arbitrary_bound!(min, max);
}
Inverted(_) => {
unreachable!()
}
}
}
}
Ok(())
}
}
impl<T: Copy + Debug + PartialOrd + From<u8> + Rem<T, Output = T> + 'static> AsFilterFn
for RangeCallType<T>
{
fn num_calls(&self) -> i64 {
self.processor.calls
}
fn as_filter_fn(&self) -> Result<Box<(dyn Fn(&mut Random) -> bool)>, ReversalError> {
Ok(match &self.range {
Full => {
let calls = self.processor.calls;
Box::new(move |r| {
r.advance_steps(calls);
true
})
}
Equals(value) => {
let value = *value;
let random_call = self.processor.random_call.clone();
Box::new(move |r| random_call(r) == value)
}
Normal(min, max) => {
let min = *min;
let max = *max;
let random_call = self.processor.random_call.clone();
Box::new(move |r| {
let value = random_call(r);
min <= value && value <= max
})
}
Inverted(inner) => match **inner {
Full => return Err(ReversalError::RangeIsEmpty),
Equals(value) => {
let random_call = self.processor.random_call.clone();
Box::new(move |r| random_call(r) != value)
}
Normal(min, max) => {
let random_call = self.processor.random_call.clone();
Box::new(move |r| {
let value = random_call(r);
min > value || value > max
})
}
Inverted(_) => {
unreachable!()
}
},
})
}
}
impl<T: Copy + Debug + PartialOrd + From<u8> + Rem<T, Output = T> + 'static> Invertible
for RangeCallType<T>
{
fn invert(mut self) -> Box<Self> {
self.range = match self.range {
Inverted(range) => *range,
Normal(min, max) => {
if min == self.processor.lower_bound {
Normal((&self.processor.next_up)(max), self.processor.upper_bound)
} else if max == self.processor.upper_bound {
Normal(self.processor.lower_bound, (&self.processor.next_down)(min))
} else {
Inverted(Box::new(self.range))
}
}
other => Inverted(Box::new(other)),
};
Box::new(self)
}
}