use crate::types::{Big, RowId, RowSet};
#[derive(Clone, Debug, Default)]
pub struct SetFamily {
set_capacity: Big,
sets: Vec<RowSet>,
}
#[derive(Clone, Debug)]
pub struct SetFamilyBuilder {
set_capacity: Big,
sets: Vec<RowSet>,
}
impl SetFamily {
pub fn new(family_size: Big, set_capacity: Big) -> Self {
SetFamilyBuilder::new(family_size, set_capacity).build()
}
pub fn from_sets(set_capacity: Big, mut sets: Vec<RowSet>) -> Self {
for set in &mut sets {
if set.len() != set_capacity {
set.resize(set_capacity);
}
}
Self { set_capacity, sets }
}
pub fn builder(family_size: Big, set_capacity: Big) -> SetFamilyBuilder {
SetFamilyBuilder::new(family_size, set_capacity)
}
pub fn into_builder(self) -> SetFamilyBuilder {
SetFamilyBuilder::from_family(self)
}
pub fn family_size(&self) -> Big {
self.sets.len()
}
pub fn set_capacity(&self) -> Big {
self.set_capacity
}
pub fn sets(&self) -> &[RowSet] {
&self.sets
}
pub fn set(&self, index: Big) -> Option<&RowSet> {
self.sets.get(index)
}
pub fn is_empty(&self) -> bool {
self.sets.iter().all(|s| s.is_empty())
}
}
impl SetFamilyBuilder {
pub fn new(family_size: Big, set_capacity: Big) -> Self {
Self {
set_capacity,
sets: vec![RowSet::new(set_capacity); family_size],
}
}
pub fn from_family(family: SetFamily) -> Self {
Self {
set_capacity: family.set_capacity,
sets: family.sets,
}
}
pub fn family_size(&self) -> Big {
self.sets.len()
}
pub fn set_capacity(&self) -> Big {
self.set_capacity
}
pub fn resize(&mut self, family_size: Big, set_capacity: Big) {
self.set_capacity = set_capacity;
self.sets.resize(family_size, RowSet::new(set_capacity));
for set in &mut self.sets {
set.resize(set_capacity);
}
}
pub fn clear_set(&mut self, set_idx: Big) {
let set = self.set_mut(set_idx);
set.clear();
}
pub fn replace_set(&mut self, set_idx: Big, set: RowSet) {
self.assert_index(set_idx);
let mut normalized = set;
if normalized.len() != self.set_capacity {
normalized.resize(self.set_capacity);
}
self.sets[set_idx] = normalized;
}
pub fn insert_into_set(&mut self, set_idx: Big, value: RowId) {
let set = self.set_mut(set_idx);
set.insert(value);
}
pub fn build(self) -> SetFamily {
SetFamily {
set_capacity: self.set_capacity,
sets: self.sets,
}
}
fn set_mut(&mut self, idx: Big) -> &mut RowSet {
self.assert_index(idx);
let set = self
.sets
.get_mut(idx)
.expect("set index must already be validated");
set.resize(self.set_capacity);
set
}
fn assert_index(&self, idx: Big) {
debug_assert!(idx < self.sets.len(), "set index out of bounds");
}
}
#[cfg(test)]
mod tests {
use super::SetFamily;
use crate::types::RowId;
use std::fmt::Write;
fn format_cdd_set_family(family: &SetFamily) -> String {
let mut out = String::new();
out.push_str("begin\n");
let _ = writeln!(
out,
" {:4} {:4}",
family.family_size(),
family.set_capacity()
);
for (idx, set) in family.sets().iter().enumerate() {
let card = set.cardinality();
assert!(
family.set_capacity() >= card,
"set capacity underflow while formatting set family"
);
let complement = family.set_capacity() - card;
if complement >= card {
let _ = write!(out, " {:4} {:4} : ", idx, card as isize);
for elem in set.iter() {
let _ = write!(out, "{} ", elem.as_index());
}
} else {
let _ = write!(out, " {:4} {:4} : ", idx, -(card as isize));
for elem in set.iter_complement() {
let _ = write!(out, "{} ", elem.as_index());
}
}
out.push('\n');
}
out.push_str("end\n");
out
}
#[test]
fn compressed_string_prefers_complement_when_smaller() {
let mut builder = SetFamily::builder(2, 5);
builder.insert_into_set(0, RowId::new(0));
builder.insert_into_set(0, RowId::new(4));
for idx in [0, 1, 2, 4] {
builder.insert_into_set(1, RowId::new(idx));
}
let family = builder.build();
let expected = "\
begin
2 5
0 2 : 0 4
1 -4 : 3
end
";
assert_eq!(format_cdd_set_family(&family), expected);
}
}