use crate::ShapeLabelIdx;
#[derive(Debug, Clone, PartialEq, Default)]
pub struct ExtendAlternative {
bucket_shapes: Vec<ShapeLabelIdx>,
constraints: Vec<ScopedConstraint>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ScopedConstraint {
expr: ShapeLabelIdx,
scope: Vec<ShapeLabelIdx>,
}
impl ScopedConstraint {
pub fn expr(&self) -> &ShapeLabelIdx {
&self.expr
}
pub fn scope(&self) -> &[ShapeLabelIdx] {
&self.scope
}
}
impl ExtendAlternative {
pub fn with_bucket(idx: ShapeLabelIdx) -> Self {
ExtendAlternative {
bucket_shapes: vec![idx],
constraints: Vec::new(),
}
}
pub fn with_constraint(idx: ShapeLabelIdx) -> Self {
ExtendAlternative {
bucket_shapes: Vec::new(),
constraints: vec![ScopedConstraint {
expr: idx,
scope: Vec::new(),
}],
}
}
pub fn with_scoped_constraints(mut self, idxs: &[ShapeLabelIdx]) -> Self {
let scope = self.bucket_shapes.clone();
for c in idxs {
push_unique_constraint(
&mut self.constraints,
ScopedConstraint {
expr: *c,
scope: scope.clone(),
},
);
}
self
}
pub fn bucket_shapes(&self) -> &[ShapeLabelIdx] {
&self.bucket_shapes
}
pub fn constraints(&self) -> &[ScopedConstraint] {
&self.constraints
}
pub fn merge(&self, other: &Self) -> Self {
let mut result = self.clone();
for b in &other.bucket_shapes {
push_unique(&mut result.bucket_shapes, *b);
}
for c in &other.constraints {
push_unique_constraint(&mut result.constraints, c.clone());
}
result
}
}
fn push_unique_constraint(v: &mut Vec<ScopedConstraint>, c: ScopedConstraint) {
if let Some(existing) = v.iter_mut().find(|e| e.expr == c.expr) {
for s in c.scope {
push_unique(&mut existing.scope, s);
}
} else {
v.push(c);
}
}
fn push_unique(v: &mut Vec<ShapeLabelIdx>, x: ShapeLabelIdx) {
if !v.contains(&x) {
v.push(x);
}
}
pub(crate) fn cross_merge(left: Vec<ExtendAlternative>, right: Vec<ExtendAlternative>) -> Vec<ExtendAlternative> {
left.iter().flat_map(|a| right.iter().map(|b| a.merge(b))).collect()
}