solverforge-scoring 0.19.14

Incremental constraint scoring for SolverForge
Documentation
use super::super::{BindingId, DenseRowStore, Leaf, RowHandle};
use super::Operator;
use crate::stream::collection_extract::CollectionExtract;
use std::marker::PhantomData;

pub struct CollectionNode<S, E> {
    extractor: E,
    binding: BindingId,
    rows: DenseRowStore<usize>,
    handles: Vec<Option<RowHandle>>,
    marker: PhantomData<fn() -> S>,
}

impl<S, E> CollectionNode<S, E> {
    /* Borrows the source extractor this node was built from. */
    pub(crate) fn extractor(&self) -> &E {
        &self.extractor
    }
    pub fn new(extractor: E, binding: u32) -> Self {
        Self {
            extractor,
            binding: BindingId(binding),
            rows: DenseRowStore::new(),
            handles: Vec::new(),
            marker: PhantomData,
        }
    }
}

impl<S: 'static, E: CollectionExtract<S> + 'static> Operator<S> for CollectionNode<S, E>
where
    E::Item: 'static,
{
    type View<'a> = Leaf<'a, E::Item>;
    type Evaluation = ();
    #[inline]
    fn prepare_evaluation(&self, _: &S) {}
    #[inline]
    fn visit_evaluation<'a>(
        &'a self,
        solution: &'a S,
        _: &'a (),
        visitor: &mut impl FnMut(Self::View<'a>),
    ) {
        for (index, entity) in self.extractor.extract(solution).iter().enumerate() {
            if self.extractor.contains(solution, entity) {
                visitor(Leaf::new(entity, index));
            }
        }
    }
    fn clear(&mut self) {
        self.rows.clear();
        self.handles.clear();
    }
    fn initialize(&mut self, solution: &S) {
        self.rows.clear();
        self.handles.clear();
        for (index, entity) in self.extractor.extract(solution).iter().enumerate() {
            let handle = self
                .extractor
                .contains(solution, entity)
                .then(|| self.rows.insert(index));
            self.handles.push(handle);
        }
    }
    fn handles(&self) -> Vec<RowHandle> {
        self.rows.iter().map(|(h, _)| h).collect()
    }
    fn resolve<'a>(&'a self, solution: &'a S, handle: RowHandle) -> Option<Self::View<'a>> {
        let index = *self.rows.get(handle)?;
        Some(Leaf::new(
            self.extractor.extract(solution).get(index)?,
            index,
        ))
    }
    fn visit_provenance(&self, handle: RowHandle, visitor: &mut impl FnMut(u32, usize, usize)) {
        if let Some(index) = self.rows.get(handle) {
            let descriptor = match self.extractor.change_source() {
                crate::stream::collection_extract::ChangeSource::Descriptor(d) => d,
                _ => usize::MAX,
            };
            visitor(self.binding.0, descriptor, *index);
        }
    }
    fn retract(
        &mut self,
        _: &S,
        descriptor: usize,
        index: usize,
        removed: &mut Vec<RowHandle>,
        _inserted: &mut Vec<RowHandle>,
    ) {
        removed.clear();
        if !self
            .extractor
            .change_source()
            .assert_localizes(descriptor, "relational source")
        {
            return;
        }
        if let Some(slot) = self.handles.get_mut(index) {
            if let Some(handle) = slot.take() {
                self.rows.retract(handle);
                removed.push(handle);
            }
        }
    }
    fn insert(
        &mut self,
        solution: &S,
        descriptor: usize,
        index: usize,
        _removed: &mut Vec<RowHandle>,
        inserted: &mut Vec<RowHandle>,
    ) {
        inserted.clear();
        if !self
            .extractor
            .change_source()
            .assert_localizes(descriptor, "relational source")
        {
            return;
        }
        if self.handles.get(index).is_some_and(Option::is_some) {
            return;
        }
        if let Some(entity) = self.extractor.extract(solution).get(index) {
            if self.extractor.contains(solution, entity) {
                let handle = self.rows.insert(index);
                self.handles.resize(self.handles.len().max(index + 1), None);
                self.handles[index] = Some(handle);
                inserted.push(handle);
            }
        }
    }
}