Spaces:
Sleeping
Sleeping
| """ | |
| blast_radius.py — Find all symbols transitively affected by a change. | |
| Given a changed symbol, walks the REVERSE graph (callers) to find | |
| everything that depends on it. | |
| Performance fix: accept an optional pre-built reverse graph so the caller | |
| can build it once and reuse it across multiple symbols instead of | |
| rebuilding it O(N) times. | |
| """ | |
| from typing import Dict, List, Optional, Set | |
| def build_reverse_graph(graph: Dict[str, List[str]]) -> Dict[str, Set[str]]: | |
| """Build the reverse (caller) graph once; reuse for many queries.""" | |
| reverse: Dict[str, Set[str]] = {} | |
| for caller, callees in graph.items(): | |
| for callee in callees: | |
| reverse.setdefault(callee, set()).add(caller) | |
| return reverse | |
| def get_blast_radius( | |
| graph: Dict[str, List[str]], | |
| changed_symbol: str, | |
| reverse: Optional[Dict[str, Set[str]]] = None, | |
| ) -> List[str]: | |
| """ | |
| All functions that (transitively) call changed_symbol. | |
| Args: | |
| graph: Forward call graph (caller -> [callees]). | |
| changed_symbol: The symbol whose blast radius we want. | |
| reverse: Pre-built reverse graph. If None it is built here | |
| (correct but wasteful when called in a loop). | |
| Uses iterative DFS with cycle detection. | |
| """ | |
| if reverse is None: | |
| reverse = build_reverse_graph(graph) | |
| affected: List[str] = [] | |
| visited: Set[str] = set() | |
| # Iterative DFS on reverse graph | |
| stack = [changed_symbol] | |
| visited.add(changed_symbol) | |
| while stack: | |
| current = stack.pop() | |
| for caller in reverse.get(current, ()): | |
| if caller not in visited: | |
| visited.add(caller) | |
| affected.append(caller) | |
| stack.append(caller) | |
| return affected | |