use crate::traits::{HierarchyBase, HierarchyIds};
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
#[derive(Clone, Debug, Hash, PartialEq)]
pub struct FlatId<T>(T);
pub struct FlatView<'a, N> {
path_separator: String,
base: &'a N,
}
impl<'a, N: HierarchyBase> FlatView<'a, N> {
pub fn new(base: &'a N) -> Self {
Self {
path_separator: "/".to_string(),
base,
}
}
pub fn new_with_separator(base: &'a N, path_separator: String) -> Self {
Self {
path_separator,
base,
}
}
fn cell_is_leaf(&self, cell: &N::CellId) -> bool {
self.base.num_child_instances(cell) == 0
}
fn cell_exists_in_flat_view(&self, cell: &N::CellId) -> bool {
!self.cell_is_flattened(cell)
}
fn cell_is_flattened(&self, cell: &N::CellId) -> bool {
let is_top = self.base.num_dependent_cells(cell) == 0;
let is_leaf = self.cell_is_leaf(cell);
!is_top && !is_leaf
}
}
type HierarchyPath<T> = Arc<Vec<T>>;
impl<'a, N: HierarchyIds> HierarchyIds for FlatView<'a, N> {
type CellId = N::CellId;
type CellInstId = HierarchyPath<N::CellInstId>;
}
impl<'a, N: HierarchyBase> HierarchyBase for FlatView<'a, N> {
type NameType = N::NameType;
fn cell_by_name(&self, name: &str) -> Option<Self::CellId> {
let cell = self.base.cell_by_name(name);
cell.filter(|cell| self.cell_exists_in_flat_view(cell))
}
fn cell_instance_by_name(
&self,
parent_cell: &Self::CellId,
name: &str,
) -> Option<Self::CellInstId> {
let path = name.split(&self.path_separator);
let mut parent_cell = parent_cell.clone();
let mut current_inst = vec![];
for name in path {
let inst = self.base.cell_instance_by_name(&parent_cell, name);
if let Some(inst) = inst {
parent_cell = self.base.template_cell(&inst);
current_inst.push(inst);
} else {
current_inst.clear();
break;
}
}
if current_inst.is_empty() {
None
} else {
Some(current_inst.into())
}
}
fn cell_name(&self, cell: &Self::CellId) -> Self::NameType {
let name = self.base.cell_name(cell);
if self.cell_is_flattened(cell) {
panic!("Cell does not exist in flat view: {}", &name);
}
name
}
fn cell_instance_name(&self, cell_inst: &Self::CellInstId) -> Option<Self::NameType> {
let path_names: Option<Vec<_>> = cell_inst
.iter()
.map(|inst| self.base.cell_instance_name(inst))
.collect();
path_names.map(|names| names.join(&self.path_separator).into())
}
fn parent_cell(&self, cell_instance: &Self::CellInstId) -> Self::CellId {
self.base.parent_cell(&cell_instance[0])
}
fn template_cell(&self, cell_instance: &Self::CellInstId) -> Self::CellId {
self.base
.template_cell(&cell_instance[cell_instance.len() - 1])
}
fn for_each_cell<F>(&self, mut f: F)
where
F: FnMut(Self::CellId),
{
self.base.for_each_cell(|c| {
if self.cell_exists_in_flat_view(&c) {
f(c);
}
})
}
fn for_each_cell_instance<F>(&self, cell: &Self::CellId, mut f: F)
where
F: FnMut(Self::CellInstId),
{
let mut stack = vec![self.base.each_cell_instance(cell)];
let mut path = Arc::new(vec![]);
while let Some(mut insts) = stack.pop() {
if let Some(inst) = insts.next() {
stack.push(insts);
let template = self.base.template_cell(&inst);
Arc::make_mut(&mut path).push(inst);
if self.base.num_child_instances(&template) == 0 {
f(Arc::clone(&path))
} else {
let sub_insts = self.base.each_cell_instance(&template);
stack.push(sub_insts);
}
} else {
Arc::make_mut(&mut path).pop();
}
}
}
fn for_each_cell_dependency<F>(&self, cell: &Self::CellId, mut f: F)
where
F: FnMut(Self::CellId),
{
let mut visited = HashSet::new();
let mut stack = self.base.each_cell_dependency_vec(cell);
while let Some(dep) = stack.pop() {
if !visited.contains(&dep) {
stack.extend(self.base.each_cell_dependency(&dep));
if self.cell_exists_in_flat_view(&dep) {
f(dep.clone());
}
visited.insert(dep);
}
}
}
fn for_each_dependent_cell<F>(&self, cell: &Self::CellId, mut f: F)
where
F: FnMut(Self::CellId),
{
let mut visited = HashSet::new();
let mut stack = self.base.each_dependent_cell_vec(cell);
while let Some(dep) = stack.pop() {
if !visited.contains(&dep) {
visited.insert(dep.clone());
if self.cell_exists_in_flat_view(&dep) {
f(dep);
} else {
stack.extend(self.base.each_dependent_cell(&dep));
}
}
}
}
fn for_each_cell_reference<F>(&self, cell: &Self::CellId, mut f: F)
where
F: FnMut(Self::CellInstId),
{
assert!(
self.cell_exists_in_flat_view(cell),
"Cell does not exist in flat view: {}",
self.base.cell_name(cell)
);
let mut references = vec![self.base.each_cell_reference(cell)];
let mut path = Arc::new(vec![]);
while let Some(mut refs) = references.pop() {
if let Some(r) = refs.next() {
references.push(refs);
let parent = self.base.parent_cell(&r);
Arc::make_mut(&mut path).insert(0, r.clone());
if self.cell_exists_in_flat_view(&parent) {
f(Arc::clone(&path));
} else {
references.push(self.base.each_cell_reference(&parent));
}
} else {
if !path.is_empty() {
Arc::make_mut(&mut path).remove(0);
}
}
}
}
fn num_child_instances(&self, cell: &Self::CellId) -> usize {
let num_non_flat_children = self.base.num_child_instances(cell);
if num_non_flat_children == 0 {
0
} else {
let mut counted_cells: HashMap<N::CellId, usize> = Default::default();
self.base.for_each_cell_instance(cell, |inst| {
let template = self.base.template_cell(&inst);
*counted_cells.entry(template).or_insert(0) += 1;
});
counted_cells
.into_iter()
.map(|(cell, num)| num * self.base.num_child_instances(&cell))
.sum()
}
}
fn num_cells(&self) -> usize {
let mut count = 0;
self.for_each_cell(|_| count += 1);
count
}
}
#[cfg(test)]
mod tests_with_hierarchy {
use crate::flat_view::FlatView;
use crate::prelude::Chip;
use crate::prelude::*;
fn create_test_chip() -> Chip {
let mut chip = Chip::new();
let top1 = chip.create_cell("TOP1".into());
let top2 = chip.create_cell("TOP2".into());
let intermediate = chip.create_cell("INTERMEDIATE".into());
let leaf1 = chip.create_cell("LEAF1".into());
let leaf2 = chip.create_cell("LEAF2".into());
chip.create_cell_instance(&intermediate, &leaf1, Some("leaf1_inst1".into()));
chip.create_cell_instance(&intermediate, &leaf1, Some("leaf1_inst2".into()));
chip.create_cell_instance(&intermediate, &leaf2, Some("leaf2_inst1".into()));
chip.create_cell_instance(&intermediate, &leaf2, Some("leaf2_inst2".into()));
chip.create_cell_instance(&top1, &intermediate, Some("intermediate_inst1".into()));
chip.create_cell_instance(&top1, &intermediate, Some("intermediate_inst2".into()));
chip.create_cell_instance(&top2, &leaf1, Some("leaf1_inst1".into()));
chip.create_cell_instance(&top2, &leaf2, Some("leaf2_inst1".into()));
chip.create_cell_instance(&top2, &leaf2, Some("leaf2_inst2".into()));
chip
}
#[test]
fn test_num_cells() {
let chip = create_test_chip();
let flatview = FlatView::new(&chip);
assert_eq!(flatview.num_cells(), 4); }
#[test]
fn test_access_top_cell() {
let chip = create_test_chip();
let flatview = FlatView::new(&chip);
let top1 = flatview.cell_by_name("TOP1").expect("Cell not found.");
assert_eq!(flatview.num_child_instances(&top1), 2 * 4);
assert_eq!(flatview.num_dependent_cells(&top1), 0);
assert_eq!(flatview.num_cell_dependencies(&top1), 2);
assert_eq!(flatview.each_cell_instance(&top1).count(), 8);
}
#[test]
fn test_find_template_cell() {
let chip = create_test_chip();
let flatview = FlatView::new(&chip);
let top1 = flatview.cell_by_name("TOP1").expect("Cell not found.");
let leaf1 = flatview.cell_by_name("LEAF1").expect("Cell not found.");
assert_eq!(
&flatview.template_cell(
&flatview
.cell_instance_by_name(&top1, "intermediate_inst1/leaf1_inst1",)
.unwrap()
),
&leaf1
);
}
#[test]
fn test_find_instance_by_name() {
let chip = create_test_chip();
let flatview = FlatView::new(&chip);
let top1 = flatview.cell_by_name("TOP1").expect("Cell not found.");
{
let names = vec![
"intermediate_inst1/leaf1_inst1",
"intermediate_inst2/leaf1_inst1",
"intermediate_inst2/leaf2_inst1",
"intermediate_inst2/leaf2_inst2",
];
for name in names {
let inst = flatview
.cell_instance_by_name(&top1, name)
.expect("instance not found");
assert_eq!(flatview.cell_instance_name(&inst), Some(name.into()));
assert_eq!(&flatview.parent_cell(&inst), &top1);
}
}
}
#[test]
fn test_count_references() {
let chip = create_test_chip();
let flatview = FlatView::new(&chip);
let top1 = flatview.cell_by_name("TOP1").expect("Cell not found.");
let leaf1 = flatview.cell_by_name("LEAF1").expect("Cell not found.");
let leaf2 = flatview.cell_by_name("LEAF2").expect("Cell not found.");
assert_eq!(flatview.num_cell_references(&leaf1), 2 * 2 + 1);
assert_eq!(flatview.num_cell_references(&leaf2), 2 * 2 + 2);
assert_eq!(flatview.num_cell_references(&top1), 0);
}
#[test]
fn test_another_top_cell() {
let chip = create_test_chip();
let flatview = FlatView::new(&chip);
let top2 = flatview.cell_by_name("TOP2").expect("Cell not found.");
assert_eq!(flatview.num_dependent_cells(&top2), 0);
assert_eq!(flatview.num_cell_dependencies(&top2), 2);
assert_eq!(flatview.each_cell_instance(&top2).count(), 3);
}
}