org.jetbrains.java.decompiler.modules.decompiler.StrongConnectivityHelper Maven / Gradle / Ivy
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.java.decompiler.modules.decompiler;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.util.ListStack;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
// --------------------------------------------------------------------
// Algorithm
// --------------------------------------------------------------------
// DFS(G)
// {
// make a new vertex x with edges x->v for all v
// initialize a counter N to zero
// initialize list L to empty
// build directed tree T, initially a single vertex {x}
// visit(x)
// }
//
// visit(p)
// {
// add p to L
// dfsnum(p) = N
// increment N
// low(p) = dfsnum(p)
// for each edge p->q
// if q is not already in T
// {
// add p->q to T
// visit(q)
// low(p) = min(low(p), low(q))
// } else low(p) = min(low(p), dfsnum(q))
//
// if low(p)=dfsnum(p)
// {
// output "component:"
// repeat
// remove last element v from L
// output v
// remove v from G
// until v=p
// }
// }
// --------------------------------------------------------------------
public class StrongConnectivityHelper {
private ListStack lstack;
private int ncounter;
private HashSet tset;
private HashMap dfsnummap;
private HashMap lowmap;
private List> components;
private HashSet setProcessed;
// *****************************************************************************
// constructors
// *****************************************************************************
public StrongConnectivityHelper() {
}
public StrongConnectivityHelper(Statement stat) {
findComponents(stat);
}
// *****************************************************************************
// public methods
// *****************************************************************************
public List> findComponents(Statement stat) {
components = new ArrayList>();
setProcessed = new HashSet();
visitTree(stat.getFirst());
for (Statement st : stat.getStats()) {
if (!setProcessed.contains(st) && st.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL).isEmpty()) {
visitTree(st);
}
}
// should not find any more nodes! FIXME: ??
for (Statement st : stat.getStats()) {
if (!setProcessed.contains(st)) {
visitTree(st);
}
}
return components;
}
public static boolean isExitComponent(List lst) {
HashSet set = new HashSet();
for (Statement stat : lst) {
set.addAll(stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD));
}
set.removeAll(lst);
return (set.size() == 0);
}
public static List getExitReps(List> lst) {
List res = new ArrayList();
for (List comp : lst) {
if (isExitComponent(comp)) {
res.add(comp.get(0));
}
}
return res;
}
// *****************************************************************************
// private methods
// *****************************************************************************
private void visitTree(Statement stat) {
lstack = new ListStack();
ncounter = 0;
tset = new HashSet();
dfsnummap = new HashMap();
lowmap = new HashMap();
visit(stat);
setProcessed.addAll(tset);
setProcessed.add(stat);
}
private void visit(Statement stat) {
lstack.push(stat);
dfsnummap.put(stat, ncounter);
lowmap.put(stat, ncounter);
ncounter++;
List lstSuccs = stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD); // TODO: set?
lstSuccs.removeAll(setProcessed);
for (int i = 0; i < lstSuccs.size(); i++) {
Statement succ = lstSuccs.get(i);
int secvalue;
if (tset.contains(succ)) {
secvalue = dfsnummap.get(succ);
}
else {
tset.add(succ);
visit(succ);
secvalue = lowmap.get(succ);
}
lowmap.put(stat, Math.min(lowmap.get(stat), secvalue));
}
if (lowmap.get(stat).intValue() == dfsnummap.get(stat).intValue()) {
List lst = new ArrayList();
Statement v;
do {
v = lstack.pop();
lst.add(v);
}
while (v != stat);
components.add(lst);
}
}
// *****************************************************************************
// getter and setter methods
// *****************************************************************************
public List> getComponents() {
return components;
}
public void setComponents(List> components) {
this.components = components;
}
}