|
29 | 29 | //! always use this particular heuristic, however! We reserve the right to change the heuristic at |
30 | 30 | //! any time. |
31 | 31 |
|
32 | | -use std::collections::{HashMap, VecDeque}; |
| 32 | +use std::collections::HashMap; |
| 33 | +use std::collections::VecDeque; |
33 | 34 |
|
34 | 35 | use smallvec::SmallVec; |
35 | 36 |
|
@@ -135,137 +136,117 @@ where |
135 | 136 | } |
136 | 137 |
|
137 | 138 | #[derive(Clone)] |
138 | | -pub struct AppendingCycleDetector { |
139 | | - nodes: VecDeque<Handle<Node>>, |
| 139 | +pub struct EdgeAppendingCycleDetector { |
| 140 | + edges: VecDeque<Edge>, |
140 | 141 | } |
141 | 142 |
|
142 | | -impl AppendingCycleDetector { |
143 | | - pub fn from_node(node: Handle<Node>) -> Self { |
| 143 | +impl EdgeAppendingCycleDetector { |
| 144 | + pub fn new() -> Self { |
144 | 145 | Self { |
145 | | - nodes: vec![node].into(), |
| 146 | + edges: vec![].into(), |
146 | 147 | } |
147 | 148 | } |
148 | 149 |
|
149 | | - pub fn appended( |
| 150 | + pub fn append_edge( |
150 | 151 | &mut self, |
151 | 152 | graph: &StackGraph, |
152 | 153 | partials: &mut PartialPaths, |
153 | | - appended_node: Handle<Node>, |
154 | | - ) -> bool { |
155 | | - // find last occurrence of the appended node |
156 | | - let i = self.nodes.iter().rposition(|n| *n == appended_node); |
157 | | - |
158 | | - // add new node |
159 | | - self.nodes.push(appended_node); |
160 | | - |
161 | | - // check if the appended node was found |
162 | | - let i = match i { |
163 | | - Some(i) => i, |
164 | | - None => return true, |
165 | | - }; |
| 154 | + edge: Edge, |
| 155 | + ) -> Result<(), ()> { |
| 156 | + let end_node = edge.sink; |
| 157 | + self.edges.push(edge); |
| 158 | + |
| 159 | + let mut cyclic_path = PartialPath::from_node(graph, partials, end_node); |
| 160 | + let mut last_idx = self.edges.len(); |
| 161 | + for idx in (0..last_idx).rev() { |
| 162 | + let edge = self.edges[idx]; |
| 163 | + if edge.source != cyclic_path.end_node { |
| 164 | + continue; |
| 165 | + } |
166 | 166 |
|
167 | | - // construct cyclic path |
168 | | - let mut cyclic_path = PartialPath::from_node(graph, partials, self.nodes[i]); |
169 | | - for node in self.nodes.range(i + 1..) { |
170 | | - if cyclic_path.ends_in_jump(graph) { |
171 | | - // restore jump target |
172 | | - cyclic_path |
173 | | - .scope_stack_precondition |
174 | | - .push_back(partials, *node); |
175 | | - cyclic_path |
176 | | - .scope_stack_postcondition |
177 | | - .push_front(partials, *node); |
178 | | - cyclic_path.resolve(graph, partials).unwrap(); |
| 167 | + let mut prefix_path = PartialPath::from_node(graph, partials, edge.source); |
| 168 | + for idx in idx..last_idx { |
| 169 | + let edge = self.edges[idx]; |
| 170 | + prefix_path |
| 171 | + .resolve_to(graph, partials, edge.source) |
| 172 | + .unwrap(); |
| 173 | + prefix_path.append(graph, partials, edge).unwrap(); |
179 | 174 | } |
180 | | - cyclic_path |
181 | | - .append( |
182 | | - graph, |
183 | | - partials, |
184 | | - Edge { |
185 | | - source: cyclic_path.end_node, |
186 | | - sink: *node, |
187 | | - precedence: 0, |
188 | | - }, |
189 | | - ) |
| 175 | + last_idx = idx; |
| 176 | + prefix_path.ensure_no_overlapping_variables(partials, &cyclic_path); |
| 177 | + prefix_path |
| 178 | + .concatenate(graph, partials, &cyclic_path) |
190 | 179 | .unwrap(); |
| 180 | + cyclic_path = prefix_path; |
| 181 | + |
| 182 | + if !cyclic_path.is_productive(graph, partials) { |
| 183 | + return Err(()); |
| 184 | + } |
191 | 185 | } |
192 | 186 |
|
193 | | - // process path if it is productive |
194 | | - cyclic_path.is_productive(graph, partials) |
| 187 | + Ok(()) |
195 | 188 | } |
196 | 189 | } |
197 | 190 |
|
198 | 191 | #[derive(Clone)] |
199 | | -pub struct JoiningCycleDetector { |
| 192 | +pub struct PartialPathAppendingCycleDetector { |
200 | 193 | paths: VecDeque<OwnedOrDatabasePath>, |
201 | 194 | } |
202 | 195 |
|
203 | | -impl JoiningCycleDetector { |
| 196 | +impl PartialPathAppendingCycleDetector { |
204 | 197 | pub fn from_partial_path( |
205 | 198 | _graph: &StackGraph, |
206 | 199 | _partials: &mut PartialPaths, |
207 | | - path: PartialPath, |
208 | | - ) -> Self { |
209 | | - Self { |
210 | | - paths: vec![path.into()].into(), |
211 | | - } |
212 | | - } |
213 | | - |
214 | | - pub fn from_partial_path_handle( |
215 | | - _graph: &StackGraph, |
216 | | - _partials: &mut PartialPaths, |
217 | | - _db: &Database, |
218 | | - path: Handle<PartialPath>, |
| 200 | + _db: &mut Database, |
| 201 | + path: OwnedOrDatabasePath, |
219 | 202 | ) -> Self { |
220 | 203 | Self { |
221 | | - paths: vec![path.into()].into(), |
| 204 | + paths: vec![path].into(), |
222 | 205 | } |
223 | 206 | } |
224 | 207 |
|
225 | | - pub fn joined( |
| 208 | + pub fn append_partial_path( |
226 | 209 | &mut self, |
227 | 210 | graph: &StackGraph, |
228 | 211 | partials: &mut PartialPaths, |
229 | 212 | db: &Database, |
230 | | - joined_path: OwnedOrDatabasePath, |
231 | | - ) -> bool { |
232 | | - // add new fragment |
233 | | - self.paths.push(joined_path.into()); |
234 | | - let joined_path = self.paths.back().unwrap().get(db); |
235 | | - |
236 | | - // find a fragment starting with our end node |
237 | | - // (includes new fragment, in case that is cyclic) |
238 | | - let end_node = joined_path.end_node; |
239 | | - let i = match self |
240 | | - .paths |
241 | | - .iter() |
242 | | - .rposition(|p| p.get(db).start_node == end_node) |
243 | | - { |
244 | | - Some(i) => i, |
245 | | - None => return true, |
246 | | - }; |
| 213 | + path: OwnedOrDatabasePath, |
| 214 | + ) -> Result<(), ()> { |
| 215 | + let end_node = path.get(db).end_node; |
| 216 | + self.paths.push(path); |
| 217 | + |
| 218 | + let mut cyclic_path = PartialPath::from_node(graph, partials, end_node); |
| 219 | + let mut last_idx = self.paths.len(); |
| 220 | + for idx in (0..last_idx).rev() { |
| 221 | + let path = self.paths[idx].get(db); |
| 222 | + if path.start_node != cyclic_path.end_node { |
| 223 | + continue; |
| 224 | + } |
247 | 225 |
|
248 | | - // construct the cyclic path |
249 | | - let mut cyclic_path = self.paths[i].get(db).clone(); |
250 | | - for path in self.paths.range(i + 1..) { |
251 | | - let path = path.get(db); |
252 | | - if cyclic_path.ends_in_jump(graph) { |
253 | | - // restore jump target |
254 | | - cyclic_path |
255 | | - .scope_stack_precondition |
256 | | - .push_back(partials, path.start_node); |
257 | | - cyclic_path |
258 | | - .scope_stack_postcondition |
259 | | - .push_front(partials, path.start_node); |
260 | | - cyclic_path.resolve(graph, partials).unwrap(); |
| 226 | + let mut prefix_path = path.clone(); |
| 227 | + for idx in (idx + 1)..last_idx { |
| 228 | + let path = self.paths[idx].get(db); |
| 229 | + prefix_path |
| 230 | + .resolve_to(graph, partials, path.start_node) |
| 231 | + .unwrap(); |
| 232 | + prefix_path.ensure_no_overlapping_variables(partials, path); |
| 233 | + prefix_path.concatenate(graph, partials, path).unwrap(); |
261 | 234 | } |
262 | | - cyclic_path.ensure_no_overlapping_variables(partials, path); |
263 | | - cyclic_path |
264 | | - .append_partial_path(graph, partials, path) |
| 235 | + last_idx = idx; |
| 236 | + prefix_path |
| 237 | + .resolve_to(graph, partials, cyclic_path.start_node) |
| 238 | + .unwrap(); |
| 239 | + prefix_path.ensure_no_overlapping_variables(partials, &cyclic_path); |
| 240 | + prefix_path |
| 241 | + .concatenate(graph, partials, &cyclic_path) |
265 | 242 | .unwrap(); |
| 243 | + cyclic_path = prefix_path; |
| 244 | + |
| 245 | + if !cyclic_path.is_productive(graph, partials) { |
| 246 | + return Err(()); |
| 247 | + } |
266 | 248 | } |
267 | 249 |
|
268 | | - // process path if it is productive |
269 | | - cyclic_path.is_productive(graph, partials) |
| 250 | + Ok(()) |
270 | 251 | } |
271 | 252 | } |
0 commit comments