pub struct ChangeMoveSelector<S, V, ES, VS> {
entity_selector: ES,
value_selector: VS,
getter: fn(&S, usize, usize) -> Option<V>,
setter: fn(&mut S, usize, usize, Option<V>),
descriptor_index: usize,
variable_index: usize,
variable_name: &'static str,
allows_unassigned: bool,
_phantom: PhantomData<(fn() -> S, fn() -> V)>,
}
struct ChangeEntityValues<V> {
entity_ref: super::entity::EntityReference,
values: Vec<V>,
current_assigned: bool,
}
pub struct ChangeMoveCursor<S, V>
where
S: PlanningSolution,
V: Clone + PartialEq + Send + Sync + Debug + 'static,
{
store: CandidateStore<S, ChangeMove<S, V>>,
entity_values: Vec<ChangeEntityValues<V>>,
entity_offset: usize,
value_offset: usize,
getter: fn(&S, usize, usize) -> Option<V>,
setter: fn(&mut S, usize, usize, Option<V>),
descriptor_index: usize,
variable_index: usize,
variable_name: &'static str,
allows_unassigned: bool,
}
impl<S, V> ChangeMoveCursor<S, V>
where
S: PlanningSolution,
V: Clone + PartialEq + Send + Sync + Debug + 'static,
{
fn new(
entity_values: Vec<ChangeEntityValues<V>>,
getter: fn(&S, usize, usize) -> Option<V>,
setter: fn(&mut S, usize, usize, Option<V>),
descriptor_index: usize,
variable_index: usize,
variable_name: &'static str,
allows_unassigned: bool,
) -> Self {
Self {
store: CandidateStore::new(),
entity_values,
entity_offset: 0,
value_offset: 0,
getter,
setter,
descriptor_index,
variable_index,
variable_name,
allows_unassigned,
}
}
}
impl<S, V> MoveCursor<S, ChangeMove<S, V>> for ChangeMoveCursor<S, V>
where
S: PlanningSolution,
V: Clone + PartialEq + Send + Sync + Debug + 'static,
{
fn next_candidate(&mut self) -> Option<CandidateId> {
while self.entity_offset < self.entity_values.len() {
let entity_values = &self.entity_values[self.entity_offset];
if self.value_offset < entity_values.values.len() {
let value = entity_values.values[self.value_offset].clone();
self.value_offset += 1;
return Some(self.store.push(ChangeMove::new(
entity_values.entity_ref.entity_index,
Some(value),
self.getter,
self.setter,
self.variable_index,
self.variable_name,
self.descriptor_index,
)));
}
let to_none_offset = entity_values.values.len();
if self.allows_unassigned
&& entity_values.current_assigned
&& self.value_offset == to_none_offset
{
self.value_offset += 1;
return Some(self.store.push(ChangeMove::new(
entity_values.entity_ref.entity_index,
None,
self.getter,
self.setter,
self.variable_index,
self.variable_name,
self.descriptor_index,
)));
}
self.entity_offset += 1;
self.value_offset = 0;
}
None
}
fn candidate(
&self,
id: CandidateId,
) -> Option<MoveCandidateRef<'_, S, ChangeMove<S, V>>> {
self.store.candidate(id)
}
fn take_candidate(&mut self, id: CandidateId) -> ChangeMove<S, V> {
self.store.take_candidate(id)
}
}
impl<S, V> Iterator for ChangeMoveCursor<S, V>
where
S: PlanningSolution,
V: Clone + PartialEq + Send + Sync + Debug + 'static,
{
type Item = ChangeMove<S, V>;
fn next(&mut self) -> Option<Self::Item> {
let id = self.next_candidate()?;
Some(self.take_candidate(id))
}
}
impl<S, V: Debug, ES: Debug, VS: Debug> Debug for ChangeMoveSelector<S, V, ES, VS> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ChangeMoveSelector")
.field("entity_selector", &self.entity_selector)
.field("value_selector", &self.value_selector)
.field("descriptor_index", &self.descriptor_index)
.field("variable_index", &self.variable_index)
.field("variable_name", &self.variable_name)
.field("allows_unassigned", &self.allows_unassigned)
.finish()
}
}
impl<S: PlanningSolution, V: Clone, ES, VS> ChangeMoveSelector<S, V, ES, VS> {
pub fn new(
entity_selector: ES,
value_selector: VS,
getter: fn(&S, usize, usize) -> Option<V>,
setter: fn(&mut S, usize, usize, Option<V>),
descriptor_index: usize,
variable_index: usize,
variable_name: &'static str,
) -> Self {
Self {
entity_selector,
value_selector,
getter,
setter,
descriptor_index,
variable_index,
variable_name,
allows_unassigned: false,
_phantom: PhantomData,
}
}
pub fn with_allows_unassigned(mut self, allows_unassigned: bool) -> Self {
self.allows_unassigned = allows_unassigned;
self
}
}
impl<S: PlanningSolution, V: Clone + Send + Sync + Debug + 'static>
ChangeMoveSelector<S, V, FromSolutionEntitySelector, StaticValueSelector<S, V>>
{
pub fn simple(
getter: fn(&S, usize, usize) -> Option<V>,
setter: fn(&mut S, usize, usize, Option<V>),
descriptor_index: usize,
variable_index: usize,
variable_name: &'static str,
values: Vec<V>,
) -> Self {
Self {
entity_selector: FromSolutionEntitySelector::new(descriptor_index),
value_selector: StaticValueSelector::new(values),
getter,
setter,
descriptor_index,
variable_index,
variable_name,
allows_unassigned: false,
_phantom: PhantomData,
}
}
}
impl<S, V, ES, VS> MoveSelector<S, ChangeMove<S, V>> for ChangeMoveSelector<S, V, ES, VS>
where
S: PlanningSolution,
V: Clone + PartialEq + Send + Sync + Debug + 'static,
ES: EntitySelector<S>,
VS: ValueSelector<S, V>,
{
type Cursor<'a>
= ChangeMoveCursor<S, V>
where
Self: 'a;
fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
self.open_cursor_with_context(score_director, MoveStreamContext::default())
}
fn open_cursor_with_context<'a, D: Director<S>>(
&'a self,
score_director: &D,
context: MoveStreamContext,
) -> Self::Cursor<'a> {
let solution = score_director.working_solution();
let mut entity_values: Vec<_> = self
.entity_selector
.iter(score_director)
.map(|entity_ref| {
let current_assigned = (self.getter)(
solution,
entity_ref.entity_index,
self.variable_index,
)
.is_some();
let values = self.value_selector.iter(
score_director,
entity_ref.descriptor_index,
entity_ref.entity_index,
).collect();
ChangeEntityValues {
entity_ref,
values,
current_assigned,
}
})
.collect();
for entity_values in &mut entity_values {
let start = context.start_offset(
entity_values.values.len(),
0xC4A4_6E00_0000_0000
^ entity_values.entity_ref.entity_index as u64
^ ((self.descriptor_index as u64) << 32)
^ self.variable_index as u64,
);
entity_values.values.rotate_left(start);
}
let entity_start = context.start_offset(
entity_values.len(),
0xC4A4_6E00_0000_0001
^ ((self.descriptor_index as u64) << 32)
^ self.variable_index as u64,
);
entity_values.rotate_left(entity_start);
ChangeMoveCursor::new(
entity_values,
self.getter,
self.setter,
self.descriptor_index,
self.variable_index,
self.variable_name,
self.allows_unassigned,
)
}
fn size<D: Director<S>>(&self, score_director: &D) -> usize {
self.entity_selector
.iter(score_director)
.map(|entity_ref| {
self.value_selector.size(
score_director,
entity_ref.descriptor_index,
entity_ref.entity_index,
) + usize::from(
self.allows_unassigned
&& (self.getter)(
score_director.working_solution(),
entity_ref.entity_index,
self.variable_index,
)
.is_some(),
)
})
.sum()
}
}