// Returns a list of paths. Each path is a sequence of objects, starting // on an object of type 'type' and ending on a root. public PathTree GetRoots(IProgressListener listener, int type) { RootInfo rootInfo = new RootInfo(); PathTree pathTree = new PathTree(this); foreach (int obj in GetObjectsByType(type)) { rootInfo.BaseObjects [obj] = obj; } int nc = 0; foreach (int obj in GetObjectsByType(type)) { if (listener.Cancelled) { return(null); } rootInfo.nc = 0; FindRoot(rootInfo, pathTree, obj); // Register partial paths to the root, to avoid having to // recalculate them again // if (nc % 100 == 0) // Console.WriteLine ("NC: " + nc + " " + rootInfo.Roots.Count); pathTree.AddBaseObject(obj); foreach (KeyValuePair <int, int[]> e in rootInfo.Roots) { pathTree.AddPath(e.Value); } rootInfo.Visited.Clear(); rootInfo.Roots.Clear(); nc++; double newp = (double)nc / (double)rootInfo.BaseObjects.Count; listener.ReportProgress("Looking for roots", newp); } pathTree.Flush(); return(pathTree); }
void FindTreeRoot(List <int> path, Dictionary <int, int[]> roots, PathTree pathTree, int node) { int obj = pathTree.GetNodeObject(node); path.Add(obj); bool hasRef = false; foreach (int cnode in pathTree.GetChildNodes(node)) { FindTreeRoot(path, roots, pathTree, cnode); hasRef = true; } if (!hasRef) { // A root RegisterPath(roots, path, obj); } path.RemoveAt(path.Count - 1); }
// It returns -2 of obj is a dead end // Returns n >= 0, if all paths starting at 'obj' end in objects already // visited. 'n' is the index of a node in rootInfo.Path, which is the closest // visited node found // Returns -1 otherwise. // This return value is used to detect dead ends. int FindRoot(RootInfo rootInfo, PathTree pathTree, int obj) { if (rootInfo.DeadEnds.ContainsKey(obj)) { return(-2); } int curval; if (rootInfo.Visited.TryGetValue(obj, out curval)) { // The object has already been visited if (rootInfo.Path.Count >= curval) { return(rootInfo.Path.IndexOf(obj)); } } rootInfo.Visited [obj] = rootInfo.Path.Count; int treePos = pathTree.GetObjectNode(obj); if (treePos != -1) { // If this object already has partial paths to roots, // reuse them. FindTreeRoot(rootInfo.Path, rootInfo.Roots, pathTree, treePos); return(-1); } rootInfo.Path.Add(obj); bool hasrefs = false; int findresult = int.MaxValue; foreach (int oref in GetReferencers(obj)) { hasrefs = true; if (!rootInfo.BaseObjects.ContainsKey(oref)) { int fr = FindRoot(rootInfo, pathTree, oref); if (fr != -2 && fr < findresult) { findresult = fr; } } } if (!hasrefs) { // A root rootInfo.Visited.Remove(obj); RegisterPath(rootInfo.Roots, rootInfo.Path, obj); findresult = -1; } rootInfo.Path.RemoveAt(rootInfo.Path.Count - 1); // If all children paths end in nodes already visited, it means that it is a dead end. if (findresult >= rootInfo.Path.Count) { rootInfo.DeadEnds [obj] = obj; // Console.WriteLine ("de: " + findresult); } return(findresult); }