use std::any::Any;
use crate::{DefaultMutator, Mutator};
macro_rules! binary_search_arbitrary {
($name_function: ident, $uxx:ty) => {
#[no_coverage]
pub(crate) fn $name_function(low: $uxx, high: $uxx, step: u64) -> $uxx {
let next = low.wrapping_add(high.wrapping_sub(low) / 2);
if low.wrapping_add(1) >= high {
if step % 2 == 0 {
high
} else {
low
}
} else if step == 0 {
next
} else if step % 2 == 1 {
$name_function(next.wrapping_add(1), high, step / 2)
} else {
$name_function(low, next.wrapping_sub(1), (step - 1) / 2)
}
}
};
}
binary_search_arbitrary!(binary_search_arbitrary_u8, u8);
binary_search_arbitrary!(binary_search_arbitrary_u16, u16);
binary_search_arbitrary!(binary_search_arbitrary_u32, u32);
binary_search_arbitrary!(binary_search_arbitrary_u64, u64);
const INITIAL_MUTATION_STEP: u64 = 0;
macro_rules! impl_int_mutator {
($name:ident, $name_unsigned: ident, $name_mutator:ident) => {
#[derive(Clone)]
pub struct $name_mutator {
shuffled_integers: [u8; 256],
rng: fastrand::Rng,
}
impl Default for $name_mutator {
#[no_coverage]
fn default() -> Self {
let mut shuffled_integers = [0; 256];
for i in 0..=255_u8 {
shuffled_integers[i as usize] = i;
}
let rng = fastrand::Rng::default();
rng.shuffle(&mut shuffled_integers);
$name_mutator {
shuffled_integers,
rng,
}
}
}
impl $name_mutator {
#[no_coverage]
fn uniform_permutation(&self, step: u64) -> $name_unsigned {
let size = <$name>::BITS as u64;
const GRANULARITY: u64 = ((usize::BITS as usize) - (256u64.leading_zeros() as usize) - 1) as u64;
const STEP_MASK: u64 = ((u8::MAX as usize) >> (8 - GRANULARITY)) as u64;
let step_i = (step & STEP_MASK) as usize;
let mut prev = unsafe { *self.shuffled_integers.get_unchecked(step_i) as $name_unsigned };
let mut result = (prev << (size - GRANULARITY)) as $name_unsigned;
for i in 1..(size / GRANULARITY) {
let step_i = (((step >> (i * GRANULARITY)) ^ prev as u64) & STEP_MASK) as usize;
prev = unsafe { *self.shuffled_integers.get_unchecked(step_i) as $name_unsigned };
result |= prev << (size - (i + 1) * GRANULARITY);
}
result
}
}
impl Mutator<$name> for $name_mutator {
#[doc(hidden)]
type Cache = ();
#[doc(hidden)]
type MutationStep = u64; #[doc(hidden)]
type ArbitraryStep = u64;
#[doc(hidden)]
type UnmutateToken = $name;
#[doc(hidden)]
#[no_coverage]
fn default_arbitrary_step(&self) -> Self::ArbitraryStep {
<_>::default()
}
#[doc(hidden)]
#[no_coverage]
fn is_valid(&self, _value: &$name) -> bool {
true
}
#[doc(hidden)]
#[no_coverage]
fn validate_value(&self, _value: &$name) -> Option<Self::Cache> {
Some(())
}
#[doc(hidden)]
#[no_coverage]
fn default_mutation_step(&self, _value: &$name, _cache: &Self::Cache) -> Self::MutationStep {
INITIAL_MUTATION_STEP
}
#[doc(hidden)]
#[no_coverage]
fn global_search_space_complexity(&self) -> f64 {
<$name>::BITS as f64
}
#[doc(hidden)]
#[no_coverage]
fn max_complexity(&self) -> f64 {
<$name>::BITS as f64
}
#[doc(hidden)]
#[no_coverage]
fn min_complexity(&self) -> f64 {
<$name>::BITS as f64
}
#[doc(hidden)]
#[no_coverage]
fn complexity(&self, _value: &$name, _cache: &Self::Cache) -> f64 {
<$name>::BITS as f64
}
#[doc(hidden)]
#[no_coverage]
fn ordered_arbitrary(&self, step: &mut Self::ArbitraryStep, max_cplx: f64) -> Option<($name, f64)> {
if max_cplx < self.min_complexity() {
return None;
}
if *step > <$name_unsigned>::MAX as u64 {
None
} else {
let value = self.uniform_permutation(*step) as $name;
*step += 1;
Some((value, <$name>::BITS as f64))
}
}
#[doc(hidden)]
#[no_coverage]
fn random_arbitrary(&self, _max_cplx: f64) -> ($name, f64) {
let value = self.rng.$name(..);
(value, <$name>::BITS as f64)
}
#[doc(hidden)]
#[no_coverage]
fn ordered_mutate(
&self,
value: &mut $name,
_cache: &mut Self::Cache,
step: &mut Self::MutationStep,
_subvalue_provider: &dyn crate::SubValueProvider,
max_cplx: f64,
) -> Option<(Self::UnmutateToken, f64)> {
if max_cplx < self.min_complexity() {
return None;
}
if *step > 10u64.saturating_add(<$name>::MAX as u64) {
return None;
}
let token = *value;
*value = {
let mut tmp_step = *step;
if tmp_step < 8 {
let nudge = (tmp_step + 2) as $name;
if nudge % 2 == 0 {
value.wrapping_add(nudge / 2)
} else {
value.wrapping_sub(nudge / 2)
}
} else {
tmp_step -= 7;
self.uniform_permutation(tmp_step) as $name
}
};
*step = step.wrapping_add(1);
Some((token, <$name>::BITS as f64))
}
#[doc(hidden)]
#[no_coverage]
fn random_mutate(
&self,
value: &mut $name,
_cache: &mut Self::Cache,
_max_cplx: f64,
) -> (Self::UnmutateToken, f64) {
(std::mem::replace(value, self.rng.$name(..)), <$name>::BITS as f64)
}
#[doc(hidden)]
#[no_coverage]
fn unmutate(&self, value: &mut $name, _cache: &mut Self::Cache, t: Self::UnmutateToken) {
*value = t;
}
#[doc(hidden)]
#[no_coverage]
fn visit_subvalues<'a>(
&self,
_value: &'a $name,
_cache: &'a Self::Cache,
_visit: &mut dyn FnMut(&'a dyn Any, f64),
) {
}
}
impl DefaultMutator for $name {
type Mutator = $name_mutator;
#[no_coverage]
fn default_mutator() -> Self::Mutator {
<$name_mutator>::default()
}
}
};
}
impl_int_mutator!(u8, u8, U8Mutator);
impl_int_mutator!(u16, u16, U16Mutator);
impl_int_mutator!(u32, u32, U32Mutator);
impl_int_mutator!(u64, u64, U64Mutator);
impl_int_mutator!(usize, usize, USizeMutator);
impl_int_mutator!(i8, u8, I8Mutator);
impl_int_mutator!(i16, u16, I16Mutator);
impl_int_mutator!(i32, u32, I32Mutator);
impl_int_mutator!(i64, u64, I64Mutator);
impl_int_mutator!(isize, isize, ISizeMutator);