pdforg_sheets/
dep_graph.rs1use pdf_core::CellAddress;
4use std::collections::{HashMap, HashSet, VecDeque};
5
6#[derive(Debug, Default, Clone)]
8pub struct DepGraph {
9 pub deps: HashMap<CellAddress, HashSet<CellAddress>>,
11 pub rdeps: HashMap<CellAddress, HashSet<CellAddress>>,
13}
14
15impl DepGraph {
16 pub fn new() -> Self { DepGraph::default() }
17
18 pub fn set_deps(&mut self, cell: CellAddress, dependencies: HashSet<CellAddress>) {
20 if let Some(old_deps) = self.deps.get(&cell) {
22 for dep in old_deps.clone() {
23 if let Some(rdeps) = self.rdeps.get_mut(&dep) {
24 rdeps.remove(&cell);
25 }
26 }
27 }
28
29 for dep in &dependencies {
31 self.rdeps.entry(dep.clone()).or_default().insert(cell.clone());
32 }
33
34 self.deps.insert(cell, dependencies);
35 }
36
37 pub fn remove_cell(&mut self, cell: &CellAddress) {
39 if let Some(old_deps) = self.deps.remove(cell) {
40 for dep in old_deps {
41 if let Some(rdeps) = self.rdeps.get_mut(&dep) {
42 rdeps.remove(cell);
43 }
44 }
45 }
46 self.rdeps.remove(cell);
47 }
48
49 pub fn dirty_set(&self, changed: &CellAddress) -> Vec<CellAddress> {
52 let mut result = vec![];
53 let mut visited = HashSet::new();
54 let mut queue = VecDeque::new();
55
56 if let Some(first_rdeps) = self.rdeps.get(changed) {
58 for dep in first_rdeps {
59 if visited.insert(dep.clone()) {
60 queue.push_back(dep.clone());
61 }
62 }
63 }
64
65 while let Some(cell) = queue.pop_front() {
66 result.push(cell.clone());
67 if let Some(rdeps) = self.rdeps.get(&cell) {
68 for dep in rdeps {
69 if visited.insert(dep.clone()) {
70 queue.push_back(dep.clone());
71 }
72 }
73 }
74 }
75
76 self.topological_sort(&result)
78 }
79
80 fn topological_sort(&self, cells: &[CellAddress]) -> Vec<CellAddress> {
82 let cell_set: HashSet<&CellAddress> = cells.iter().collect();
83 let mut in_degree: HashMap<&CellAddress, usize> = HashMap::new();
84 let mut adj: HashMap<&CellAddress, Vec<&CellAddress>> = HashMap::new();
85
86 for cell in cells {
87 in_degree.entry(cell).or_insert(0);
88 if let Some(rdeps) = self.rdeps.get(cell) {
89 for rdep in rdeps {
90 if cell_set.contains(rdep) {
91 adj.entry(cell).or_default().push(rdep);
92 *in_degree.entry(rdep).or_insert(0) += 1;
93 }
94 }
95 }
96 }
97
98 let mut queue: VecDeque<&CellAddress> = in_degree.iter()
99 .filter(|(_, °)| deg == 0)
100 .map(|(cell, _)| *cell)
101 .collect();
102
103 let mut result = vec![];
104 while let Some(cell) = queue.pop_front() {
105 result.push(cell.clone());
106 if let Some(neighbors) = adj.get(cell) {
107 for &neighbor in neighbors {
108 let deg = in_degree.entry(neighbor).or_insert(0);
109 *deg -= 1;
110 if *deg == 0 {
111 queue.push_back(neighbor);
112 }
113 }
114 }
115 }
116
117 result
118 }
119
120 pub fn would_create_cycle(&self, cell: &CellAddress, new_dep: &CellAddress) -> bool {
122 let mut visited = HashSet::new();
124 let mut stack = vec![new_dep.clone()];
125 while let Some(cur) = stack.pop() {
126 if &cur == cell { return true; }
127 if visited.insert(cur.clone()) {
128 if let Some(deps) = self.deps.get(&cur) {
129 for d in deps { stack.push(d.clone()); }
130 }
131 }
132 }
133 false
134 }
135
136 pub fn dep_count(&self) -> usize { self.deps.len() }
137 pub fn rdep_count(&self) -> usize { self.rdeps.len() }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 fn addr(row: u32, col: u32) -> CellAddress { CellAddress::new(row, col) }
145
146 #[test]
147 fn test_simple_dirty_set() {
148 let mut graph = DepGraph::new();
149 graph.set_deps(addr(0, 0), [addr(0, 1)].into_iter().collect());
151 graph.set_deps(addr(0, 2), [addr(0, 0)].into_iter().collect());
153
154 let dirty = graph.dirty_set(&addr(0, 1));
156 assert!(dirty.contains(&addr(0, 0)));
157 assert!(dirty.contains(&addr(0, 2)));
158 let a1_pos = dirty.iter().position(|a| a == &addr(0, 0)).unwrap();
160 let c1_pos = dirty.iter().position(|a| a == &addr(0, 2)).unwrap();
161 assert!(a1_pos < c1_pos);
162 }
163
164 #[test]
165 fn test_no_cycle() {
166 let mut graph = DepGraph::new();
167 graph.set_deps(addr(0, 0), [addr(0, 1)].into_iter().collect());
168 assert!(!graph.would_create_cycle(&addr(0, 1), &addr(0, 2)));
169 assert!(graph.would_create_cycle(&addr(0, 1), &addr(0, 0)));
170 }
171}