Iterative Tarjan visit function. Equivalent to the classic recursive Tarjan's SCC algorithm, but uses an explicit work stack instead of the call stack. This avoids stack overflow for files with tens of thousands of vertices.
(
graph: &mut AliveGraph,
start: VertexId,
state: &mut TarjanState,
result: &mut OrderResult,
)
| 411 | /// an explicit work stack instead of the call stack. This avoids stack |
| 412 | /// overflow for files with tens of thousands of vertices. |
| 413 | fn tarjan_visit( |
| 414 | graph: &mut AliveGraph, |
| 415 | start: VertexId, |
| 416 | state: &mut TarjanState, |
| 417 | result: &mut OrderResult, |
| 418 | ) { |
| 419 | let mut work: Vec<TarjanFrame> = Vec::new(); |
| 420 | |
| 421 | // Initialize the start vertex |
| 422 | { |
| 423 | let vertex = graph.vertex_mut(start); |
| 424 | vertex.index = state.index; |
| 425 | vertex.lowlink = state.index; |
| 426 | vertex.mark_visited(); |
| 427 | vertex.push_stack(); |
| 428 | } |
| 429 | state.index += 1; |
| 430 | state.stack.push(start); |
| 431 | |
| 432 | let children: Vec<VertexId> = graph |
| 433 | .children(start) |
| 434 | .map(|(_, child)| *child) |
| 435 | .filter(|c| !c.is_dummy()) |
| 436 | .collect(); |
| 437 | work.push(TarjanFrame { |
| 438 | v: start, |
| 439 | children, |
| 440 | child_idx: 0, |
| 441 | }); |
| 442 | |
| 443 | while let Some(frame) = work.last_mut() { |
| 444 | if frame.child_idx < frame.children.len() { |
| 445 | let w = frame.children[frame.child_idx]; |
| 446 | frame.child_idx += 1; |
| 447 | |
| 448 | let w_visited = graph.get_vertex(w).is_visited(); |
| 449 | let w_on_stack = graph.get_vertex(w).is_on_stack(); |
| 450 | |
| 451 | if !w_visited { |
| 452 | // Initialize w and push a new frame (replaces recursive call) |
| 453 | { |
| 454 | let vertex = graph.vertex_mut(w); |
| 455 | vertex.index = state.index; |
| 456 | vertex.lowlink = state.index; |
| 457 | vertex.mark_visited(); |
| 458 | vertex.push_stack(); |
| 459 | } |
| 460 | state.index += 1; |
| 461 | state.stack.push(w); |
| 462 | |
| 463 | let w_children: Vec<VertexId> = graph |
| 464 | .children(w) |
| 465 | .map(|(_, child)| *child) |
| 466 | .filter(|c| !c.is_dummy()) |
| 467 | .collect(); |
| 468 | work.push(TarjanFrame { |
| 469 | v: w, |
| 470 | children: w_children, |
no test coverage detected