Skip to content
This repository was archived by the owner on Jun 18, 2026. It is now read-only.

Commit 4db289a

Browse files
refactor: extract shared DirectedAdj and safeNeighbors into GraphUtils
Add GraphUtils.DirectedAdj class and buildDirectedAdjacencyMap() method, generalized from TopologicalSortAnalyzer's private DirectedAdj. Add GraphUtils.safeNeighbors() to eliminate null-check boilerplate. Refactor TopologicalSortAnalyzer to use shared DirectedAdj (removes ~25 lines of duplicated adjacency construction). Refactor CycleAnalyzer's getNeighbors helper to use GraphUtils.safeNeighbors. This establishes the shared utilities for consolidating adjacency/BFS construction across the remaining 11 analyzers listed in #43. Partial fix for #43
1 parent 5461013 commit 4db289a

177 files changed

Lines changed: 8761 additions & 499 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Gvisual/src/gvisual/CycleAnalyzer.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -661,8 +661,7 @@ private Iterable<String> getSuccessors(String v) {
661661
}
662662

663663
private Iterable<String> getNeighbors(String v) {
664-
Collection<String> nbrs = graph.getNeighbors(v);
665-
return nbrs != null ? nbrs : Collections.<String>emptyList();
664+
return GraphUtils.safeNeighbors(graph, v);
666665
}
667666

668667
private String edgeKey(String v1, String v2) {

Gvisual/src/gvisual/GraphUtils.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,66 @@ public static Map<String, Set<String>> buildAdjacencyMap(
8585
return adj;
8686
}
8787

88+
/**
89+
* Directed adjacency data: vertices, successor map, and predecessor map.
90+
*/
91+
public static class DirectedAdj {
92+
public final Set<String> vertices;
93+
public final Map<String, Set<String>> successors;
94+
public final Map<String, Set<String>> predecessors;
95+
96+
public DirectedAdj(Set<String> vertices,
97+
Map<String, Set<String>> successors,
98+
Map<String, Set<String>> predecessors) {
99+
this.vertices = vertices;
100+
this.successors = successors;
101+
this.predecessors = predecessors;
102+
}
103+
}
104+
105+
/**
106+
* Builds directed adjacency maps from the graph. Each edge is
107+
* interpreted as vertex1 → vertex2.
108+
*
109+
* @param graph the JUNG graph
110+
* @return DirectedAdj containing vertices, successors, and predecessors
111+
*/
112+
public static DirectedAdj buildDirectedAdjacencyMap(Graph<String, edge> graph) {
113+
Map<String, Set<String>> successors = new HashMap<String, Set<String>>();
114+
Map<String, Set<String>> predecessors = new HashMap<String, Set<String>>();
115+
Set<String> allVertices = new HashSet<String>();
116+
117+
for (String v : graph.getVertices()) {
118+
allVertices.add(v);
119+
successors.put(v, new HashSet<String>());
120+
predecessors.put(v, new HashSet<String>());
121+
}
122+
123+
for (edge e : graph.getEdges()) {
124+
String from = e.getVertex1();
125+
String to = e.getVertex2();
126+
if (from != null && to != null
127+
&& allVertices.contains(from) && allVertices.contains(to)) {
128+
successors.get(from).add(to);
129+
predecessors.get(to).add(from);
130+
}
131+
}
132+
133+
return new DirectedAdj(allVertices, successors, predecessors);
134+
}
135+
136+
/**
137+
* Safe neighbor lookup that never returns null.
138+
*
139+
* @param graph the JUNG graph
140+
* @param v the vertex
141+
* @return neighbors collection, empty if null
142+
*/
143+
public static Collection<String> safeNeighbors(Graph<String, edge> graph, String v) {
144+
Collection<String> nbrs = graph.getNeighbors(v);
145+
return nbrs != null ? nbrs : Collections.<String>emptyList();
146+
}
147+
88148
/**
89149
* BFS from a source vertex, returning distances (hop counts) to all
90150
* reachable vertices.

Gvisual/src/gvisual/TopologicalSortAnalyzer.java

Lines changed: 6 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -183,46 +183,11 @@ public VertexDependencyInfo(String vertex, Set<String> allDependencies,
183183
* {@link #analyze()}, {@link #analyzeDependencies(String)}, and
184184
* {@link #countChoicePoints()}.
185185
*/
186-
private static class DirectedAdj {
187-
final Set<String> vertices;
188-
final Map<String, Set<String>> successors;
189-
final Map<String, Set<String>> predecessors;
190-
191-
DirectedAdj(Set<String> vertices,
192-
Map<String, Set<String>> successors,
193-
Map<String, Set<String>> predecessors) {
194-
this.vertices = vertices;
195-
this.successors = successors;
196-
this.predecessors = predecessors;
197-
}
198-
}
199-
200186
/**
201-
* Builds the directed adjacency maps from the graph. Each edge is
202-
* interpreted as vertex1 → vertex2 (vertex1 must come before vertex2).
187+
* Builds the directed adjacency maps from the graph using shared GraphUtils.
203188
*/
204-
private DirectedAdj buildDirectedAdj() {
205-
Map<String, Set<String>> successors = new HashMap<String, Set<String>>();
206-
Map<String, Set<String>> predecessors = new HashMap<String, Set<String>>();
207-
Set<String> allVertices = new HashSet<String>();
208-
209-
for (String v : graph.getVertices()) {
210-
allVertices.add(v);
211-
successors.put(v, new HashSet<String>());
212-
predecessors.put(v, new HashSet<String>());
213-
}
214-
215-
for (edge e : graph.getEdges()) {
216-
String from = e.getVertex1();
217-
String to = e.getVertex2();
218-
if (from != null && to != null
219-
&& allVertices.contains(from) && allVertices.contains(to)) {
220-
successors.get(from).add(to);
221-
predecessors.get(to).add(from);
222-
}
223-
}
224-
225-
return new DirectedAdj(allVertices, successors, predecessors);
189+
private GraphUtils.DirectedAdj buildDirectedAdj() {
190+
return GraphUtils.buildDirectedAdjacencyMap(graph);
226191
}
227192

228193
// ── Core algorithms ─────────────────────────────────────────
@@ -240,7 +205,7 @@ private DirectedAdj buildDirectedAdj() {
240205
* @return complete topological sort analysis
241206
*/
242207
public TopologicalSortResult analyze() {
243-
DirectedAdj adj = buildDirectedAdj();
208+
GraphUtils.DirectedAdj adj = buildDirectedAdj();
244209
Map<String, Set<String>> successors = adj.successors;
245210
Map<String, Set<String>> predecessors = adj.predecessors;
246211
Set<String> allVertices = adj.vertices;
@@ -351,7 +316,7 @@ public VertexDependencyInfo analyzeDependencies(String vertex) {
351316
return null;
352317
}
353318

354-
DirectedAdj adj = buildDirectedAdj();
319+
GraphUtils.DirectedAdj adj = buildDirectedAdj();
355320
Map<String, Set<String>> successors = adj.successors;
356321
Map<String, Set<String>> predecessors = adj.predecessors;
357322

@@ -416,7 +381,7 @@ public int countChoicePoints() {
416381

417382
// Re-use shared adjacency builder and count points where
418383
// multiple vertices are ready simultaneously
419-
DirectedAdj adj = buildDirectedAdj();
384+
GraphUtils.DirectedAdj adj = buildDirectedAdj();
420385
Map<String, Set<String>> successors = adj.successors;
421386
Map<String, Integer> inDegree = new HashMap<String, Integer>();
422387

0 commit comments

Comments
 (0)