use std::any::{Any, TypeId};
use std::collections::HashMap;
use crate::Mutator;
#[derive(Clone, Copy)]
pub struct SubValueProviderId {
pub idx: usize,
pub generation: Generation,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Generation(pub usize);
pub trait SubValueProvider {
fn identifier(&self) -> SubValueProviderId;
fn get_random_subvalue(&self, typeid: TypeId, max_cplx: f64) -> Option<(&dyn Any, f64)>;
fn get_subvalue(&self, typeid: TypeId, max_cplx: f64, index: &mut usize) -> Option<(&dyn Any, f64)>;
}
pub struct EmptySubValueProvider;
impl SubValueProvider for EmptySubValueProvider {
#[coverage(off)]
fn identifier(&self) -> SubValueProviderId {
SubValueProviderId {
idx: 0,
generation: Generation(0),
}
}
#[coverage(off)]
fn get_random_subvalue(&self, _typeid: TypeId, _max_cplx: f64) -> Option<(&dyn Any, f64)> {
None
}
#[coverage(off)]
fn get_subvalue(&self, _typeid: TypeId, _max_cplx: f64, _index: &mut usize) -> Option<(&dyn Any, f64)> {
None
}
}
pub struct CrossoverSubValueProvider<T, M>
where
T: 'static + Clone,
M: Mutator<T>,
{
identifier: SubValueProviderId,
immutable_data: Box<(T, M::Cache)>,
whole_complexity: f64,
subvalues: HashMap<TypeId, Vec<(*const dyn Any, f64)>>,
rng: fastrand::Rng,
}
impl<T, M> CrossoverSubValueProvider<T, M>
where
T: Clone + 'static,
M: Mutator<T>,
{
#[coverage(off)]
pub fn new(identifier: SubValueProviderId, value: &T, cache: &M::Cache, mutator: &M) -> Self {
let boxed_data = Box::new((value.clone(), cache.clone()));
let mut subvalues: HashMap<TypeId, Vec<(*const dyn Any, f64)>> = HashMap::new();
let mut act_on_subvalue = #[coverage(off)]
|subvalue: &dyn Any, complexity| {
subvalues
.entry(subvalue.type_id())
.or_default()
.push((subvalue as *const _, complexity));
};
mutator.visit_subvalues(&boxed_data.0, &boxed_data.1, &mut act_on_subvalue);
for (_typeid, subvalues) in subvalues.iter_mut() {
subvalues.sort_by(
#[coverage(off)]
|x, y| (x.1, x.0).partial_cmp(&(y.1, y.0)).unwrap_or(std::cmp::Ordering::Equal),
);
subvalues.dedup();
}
let whole_complexity = mutator.complexity(value, cache);
Self {
identifier,
immutable_data: boxed_data,
whole_complexity,
subvalues,
rng: fastrand::Rng::new(),
}
}
}
impl<T, M> SubValueProvider for CrossoverSubValueProvider<T, M>
where
T: Clone + 'static,
M: Mutator<T>,
{
#[coverage(off)]
fn identifier(&self) -> SubValueProviderId {
self.identifier
}
#[coverage(off)]
fn get_random_subvalue(&self, typeid: TypeId, max_cplx: f64) -> Option<(&dyn Any, f64)> {
let subvalues = self.subvalues.get(&typeid)?;
assert!(!subvalues.is_empty());
let end_index_for_complexity = subvalues
.iter()
.position(
#[coverage(off)]
|x| x.1 >= max_cplx,
)
.unwrap_or(subvalues.len());
if end_index_for_complexity == 0 {
return None;
}
let idx = self.rng.usize(..end_index_for_complexity);
let (subvalue, complexity) = &subvalues[idx];
let subvalue = unsafe { subvalue.as_ref() }.unwrap();
Some((subvalue, *complexity))
}
#[coverage(off)]
fn get_subvalue(&self, typeid: TypeId, max_cplx: f64, index: &mut usize) -> Option<(&dyn Any, f64)> {
let subvalues = self.subvalues.get(&typeid)?;
assert!(!subvalues.is_empty());
if TypeId::of::<T>() == typeid && *index == subvalues.len() {
*index += 1;
Some((&self.immutable_data.0, self.whole_complexity))
} else {
let (subvalue, complexity) = subvalues.get(*index)?;
if *complexity < max_cplx {
let subvalue = unsafe { subvalue.as_ref() }.unwrap();
*index += 1;
Some((subvalue, *complexity))
} else {
None
}
}
}
}